/home/mip/www/img/credit/datatables/PhpParser.tar
Builder.php000064400000000312151520657540006651 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface Builder {
    /**
     * Returns the built node.
     *
     * @return Node The built node
     */
    public function getNode(): Node;
}
ParserFactory.php000064400000002650151520657540010056 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Parser\Php7;
use PhpParser\Parser\Php8;

class ParserFactory {
    /**
     * Create a parser targeting the given version on a best-effort basis. The parser will generally
     * accept code for the newest supported version, but will try to accommodate code that becomes
     * invalid in newer versions or changes in interpretation.
     */
    public function createForVersion(PhpVersion $version): Parser {
        if ($version->isHostVersion()) {
            $lexer = new Lexer();
        } else {
            $lexer = new Lexer\Emulative($version);
        }
        if ($version->id >= 80000) {
            return new Php8($lexer, $version);
        }
        return new Php7($lexer, $version);
    }

    /**
     * Create a parser targeting the newest version supported by this library. Code for older
     * versions will be accepted if there have been no relevant backwards-compatibility breaks in
     * PHP.
     */
    public function createForNewestSupportedVersion(): Parser {
        return $this->createForVersion(PhpVersion::getNewestSupported());
    }

    /**
     * Create a parser targeting the host PHP version, that is the PHP version we're currently
     * running on. This parser will not use any token emulation.
     */
    public function createForHostVersion(): Parser {
        return $this->createForVersion(PhpVersion::getHostVersion());
    }
}
NameContext.php000064400000023511151520657540007516 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt;

class NameContext {
    /** @var null|Name Current namespace */
    protected ?Name $namespace;

    /** @var Name[][] Map of format [aliasType => [aliasName => originalName]] */
    protected array $aliases = [];

    /** @var Name[][] Same as $aliases but preserving original case */
    protected array $origAliases = [];

    /** @var ErrorHandler Error handler */
    protected ErrorHandler $errorHandler;

    /**
     * Create a name context.
     *
     * @param ErrorHandler $errorHandler Error handling used to report errors
     */
    public function __construct(ErrorHandler $errorHandler) {
        $this->errorHandler = $errorHandler;
    }

    /**
     * Start a new namespace.
     *
     * This also resets the alias table.
     *
     * @param Name|null $namespace Null is the global namespace
     */
    public function startNamespace(?Name $namespace = null): void {
        $this->namespace = $namespace;
        $this->origAliases = $this->aliases = [
            Stmt\Use_::TYPE_NORMAL   => [],
            Stmt\Use_::TYPE_FUNCTION => [],
            Stmt\Use_::TYPE_CONSTANT => [],
        ];
    }

    /**
     * Add an alias / import.
     *
     * @param Name $name Original name
     * @param string $aliasName Aliased name
     * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
     * @param array<string, mixed> $errorAttrs Attributes to use to report an error
     */
    public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []): void {
        // Constant names are case sensitive, everything else case insensitive
        if ($type === Stmt\Use_::TYPE_CONSTANT) {
            $aliasLookupName = $aliasName;
        } else {
            $aliasLookupName = strtolower($aliasName);
        }

        if (isset($this->aliases[$type][$aliasLookupName])) {
            $typeStringMap = [
                Stmt\Use_::TYPE_NORMAL   => '',
                Stmt\Use_::TYPE_FUNCTION => 'function ',
                Stmt\Use_::TYPE_CONSTANT => 'const ',
            ];

            $this->errorHandler->handleError(new Error(
                sprintf(
                    'Cannot use %s%s as %s because the name is already in use',
                    $typeStringMap[$type], $name, $aliasName
                ),
                $errorAttrs
            ));
            return;
        }

        $this->aliases[$type][$aliasLookupName] = $name;
        $this->origAliases[$type][$aliasName] = $name;
    }

    /**
     * Get current namespace.
     *
     * @return null|Name Namespace (or null if global namespace)
     */
    public function getNamespace(): ?Name {
        return $this->namespace;
    }

    /**
     * Get resolved name.
     *
     * @param Name $name Name to resolve
     * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_{FUNCTION|CONSTANT}
     *
     * @return null|Name Resolved name, or null if static resolution is not possible
     */
    public function getResolvedName(Name $name, int $type): ?Name {
        // don't resolve special class names
        if ($type === Stmt\Use_::TYPE_NORMAL && $name->isSpecialClassName()) {
            if (!$name->isUnqualified()) {
                $this->errorHandler->handleError(new Error(
                    sprintf("'\\%s' is an invalid class name", $name->toString()),
                    $name->getAttributes()
                ));
            }
            return $name;
        }

        // fully qualified names are already resolved
        if ($name->isFullyQualified()) {
            return $name;
        }

        // Try to resolve aliases
        if (null !== $resolvedName = $this->resolveAlias($name, $type)) {
            return $resolvedName;
        }

        if ($type !== Stmt\Use_::TYPE_NORMAL && $name->isUnqualified()) {
            if (null === $this->namespace) {
                // outside of a namespace unaliased unqualified is same as fully qualified
                return new FullyQualified($name, $name->getAttributes());
            }

            // Cannot resolve statically
            return null;
        }

        // if no alias exists prepend current namespace
        return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
    }

    /**
     * Get resolved class name.
     *
     * @param Name $name Class ame to resolve
     *
     * @return Name Resolved name
     */
    public function getResolvedClassName(Name $name): Name {
        return $this->getResolvedName($name, Stmt\Use_::TYPE_NORMAL);
    }

    /**
     * Get possible ways of writing a fully qualified name (e.g., by making use of aliases).
     *
     * @param string $name Fully-qualified name (without leading namespace separator)
     * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
     *
     * @return Name[] Possible representations of the name
     */
    public function getPossibleNames(string $name, int $type): array {
        $lcName = strtolower($name);

        if ($type === Stmt\Use_::TYPE_NORMAL) {
            // self, parent and static must always be unqualified
            if ($lcName === "self" || $lcName === "parent" || $lcName === "static") {
                return [new Name($name)];
            }
        }

        // Collect possible ways to write this name, starting with the fully-qualified name
        $possibleNames = [new FullyQualified($name)];

        if (null !== $nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type)) {
            // Make sure there is no alias that makes the normally namespace-relative name
            // into something else
            if (null === $this->resolveAlias($nsRelativeName, $type)) {
                $possibleNames[] = $nsRelativeName;
            }
        }

        // Check for relevant namespace use statements
        foreach ($this->origAliases[Stmt\Use_::TYPE_NORMAL] as $alias => $orig) {
            $lcOrig = $orig->toLowerString();
            if (0 === strpos($lcName, $lcOrig . '\\')) {
                $possibleNames[] = new Name($alias . substr($name, strlen($lcOrig)));
            }
        }

        // Check for relevant type-specific use statements
        foreach ($this->origAliases[$type] as $alias => $orig) {
            if ($type === Stmt\Use_::TYPE_CONSTANT) {
                // Constants are are complicated-sensitive
                $normalizedOrig = $this->normalizeConstName($orig->toString());
                if ($normalizedOrig === $this->normalizeConstName($name)) {
                    $possibleNames[] = new Name($alias);
                }
            } else {
                // Everything else is case-insensitive
                if ($orig->toLowerString() === $lcName) {
                    $possibleNames[] = new Name($alias);
                }
            }
        }

        return $possibleNames;
    }

    /**
     * Get shortest representation of this fully-qualified name.
     *
     * @param string $name Fully-qualified name (without leading namespace separator)
     * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
     *
     * @return Name Shortest representation
     */
    public function getShortName(string $name, int $type): Name {
        $possibleNames = $this->getPossibleNames($name, $type);

        // Find shortest name
        $shortestName = null;
        $shortestLength = \INF;
        foreach ($possibleNames as $possibleName) {
            $length = strlen($possibleName->toCodeString());
            if ($length < $shortestLength) {
                $shortestName = $possibleName;
                $shortestLength = $length;
            }
        }

        return $shortestName;
    }

    private function resolveAlias(Name $name, int $type): ?FullyQualified {
        $firstPart = $name->getFirst();

        if ($name->isQualified()) {
            // resolve aliases for qualified names, always against class alias table
            $checkName = strtolower($firstPart);
            if (isset($this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName])) {
                $alias = $this->aliases[Stmt\Use_::TYPE_NORMAL][$checkName];
                return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
            }
        } elseif ($name->isUnqualified()) {
            // constant aliases are case-sensitive, function aliases case-insensitive
            $checkName = $type === Stmt\Use_::TYPE_CONSTANT ? $firstPart : strtolower($firstPart);
            if (isset($this->aliases[$type][$checkName])) {
                // resolve unqualified aliases
                return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes());
            }
        }

        // No applicable aliases
        return null;
    }

    private function getNamespaceRelativeName(string $name, string $lcName, int $type): ?Name {
        if (null === $this->namespace) {
            return new Name($name);
        }

        if ($type === Stmt\Use_::TYPE_CONSTANT) {
            // The constants true/false/null always resolve to the global symbols, even inside a
            // namespace, so they may be used without qualification
            if ($lcName === "true" || $lcName === "false" || $lcName === "null") {
                return new Name($name);
            }
        }

        $namespacePrefix = strtolower($this->namespace . '\\');
        if (0 === strpos($lcName, $namespacePrefix)) {
            return new Name(substr($name, strlen($namespacePrefix)));
        }

        return null;
    }

    private function normalizeConstName(string $name): string {
        $nsSep = strrpos($name, '\\');
        if (false === $nsSep) {
            return $name;
        }

        // Constants have case-insensitive namespace and case-sensitive short-name
        $ns = substr($name, 0, $nsSep);
        $shortName = substr($name, $nsSep + 1);
        return strtolower($ns) . '\\' . $shortName;
    }
}
ParserAbstract.php000064400000141330151520657540010211 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

/*
 * This parser is based on a skeleton written by Moriyoshi Koizumi, which in
 * turn is based on work by Masato Bito.
 */

use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\Cast\Double;
use PhpParser\Node\Identifier;
use PhpParser\Node\InterpolatedStringPart;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\InterpolatedString;
use PhpParser\Node\Scalar\Int_;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassConst;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Else_;
use PhpParser\Node\Stmt\ElseIf_;
use PhpParser\Node\Stmt\Enum_;
use PhpParser\Node\Stmt\Interface_;
use PhpParser\Node\Stmt\Namespace_;
use PhpParser\Node\Stmt\Nop;
use PhpParser\Node\Stmt\Property;
use PhpParser\Node\Stmt\TryCatch;
use PhpParser\Node\UseItem;
use PhpParser\NodeVisitor\CommentAnnotatingVisitor;

abstract class ParserAbstract implements Parser {
    private const SYMBOL_NONE = -1;

    /** @var Lexer Lexer that is used when parsing */
    protected Lexer $lexer;
    /** @var PhpVersion PHP version to target on a best-effort basis */
    protected PhpVersion $phpVersion;

    /*
     * The following members will be filled with generated parsing data:
     */

    /** @var int Size of $tokenToSymbol map */
    protected int $tokenToSymbolMapSize;
    /** @var int Size of $action table */
    protected int $actionTableSize;
    /** @var int Size of $goto table */
    protected int $gotoTableSize;

    /** @var int Symbol number signifying an invalid token */
    protected int $invalidSymbol;
    /** @var int Symbol number of error recovery token */
    protected int $errorSymbol;
    /** @var int Action number signifying default action */
    protected int $defaultAction;
    /** @var int Rule number signifying that an unexpected token was encountered */
    protected int $unexpectedTokenRule;

    protected int $YY2TBLSTATE;
    /** @var int Number of non-leaf states */
    protected int $numNonLeafStates;

    /** @var int[] Map of PHP token IDs to internal symbols */
    protected array $phpTokenToSymbol;
    /** @var array<int, bool> Map of PHP token IDs to drop */
    protected array $dropTokens;
    /** @var int[] Map of external symbols (static::T_*) to internal symbols */
    protected array $tokenToSymbol;
    /** @var string[] Map of symbols to their names */
    protected array $symbolToName;
    /** @var array<int, string> Names of the production rules (only necessary for debugging) */
    protected array $productions;

    /** @var int[] Map of states to a displacement into the $action table. The corresponding action for this
     *             state/symbol pair is $action[$actionBase[$state] + $symbol]. If $actionBase[$state] is 0, the
     *             action is defaulted, i.e. $actionDefault[$state] should be used instead. */
    protected array $actionBase;
    /** @var int[] Table of actions. Indexed according to $actionBase comment. */
    protected array $action;
    /** @var int[] Table indexed analogously to $action. If $actionCheck[$actionBase[$state] + $symbol] != $symbol
     *             then the action is defaulted, i.e. $actionDefault[$state] should be used instead. */
    protected array $actionCheck;
    /** @var int[] Map of states to their default action */
    protected array $actionDefault;
    /** @var callable[] Semantic action callbacks */
    protected array $reduceCallbacks;

    /** @var int[] Map of non-terminals to a displacement into the $goto table. The corresponding goto state for this
     *             non-terminal/state pair is $goto[$gotoBase[$nonTerminal] + $state] (unless defaulted) */
    protected array $gotoBase;
    /** @var int[] Table of states to goto after reduction. Indexed according to $gotoBase comment. */
    protected array $goto;
    /** @var int[] Table indexed analogously to $goto. If $gotoCheck[$gotoBase[$nonTerminal] + $state] != $nonTerminal
     *             then the goto state is defaulted, i.e. $gotoDefault[$nonTerminal] should be used. */
    protected array $gotoCheck;
    /** @var int[] Map of non-terminals to the default state to goto after their reduction */
    protected array $gotoDefault;

    /** @var int[] Map of rules to the non-terminal on their left-hand side, i.e. the non-terminal to use for
     *             determining the state to goto after reduction. */
    protected array $ruleToNonTerminal;
    /** @var int[] Map of rules to the length of their right-hand side, which is the number of elements that have to
     *             be popped from the stack(s) on reduction. */
    protected array $ruleToLength;

    /*
     * The following members are part of the parser state:
     */

    /** @var mixed Temporary value containing the result of last semantic action (reduction) */
    protected $semValue;
    /** @var mixed[] Semantic value stack (contains values of tokens and semantic action results) */
    protected array $semStack;
    /** @var int[] Token start position stack */
    protected array $tokenStartStack;
    /** @var int[] Token end position stack */
    protected array $tokenEndStack;

    /** @var ErrorHandler Error handler */
    protected ErrorHandler $errorHandler;
    /** @var int Error state, used to avoid error floods */
    protected int $errorState;

    /** @var \SplObjectStorage<Array_, null>|null Array nodes created during parsing, for postprocessing of empty elements. */
    protected ?\SplObjectStorage $createdArrays;

    /** @var Token[] Tokens for the current parse */
    protected array $tokens;
    /** @var int Current position in token array */
    protected int $tokenPos;

    /**
     * Initialize $reduceCallbacks map.
     */
    abstract protected function initReduceCallbacks(): void;

    /**
     * Creates a parser instance.
     *
     * Options:
     *  * phpVersion: ?PhpVersion,
     *
     * @param Lexer $lexer A lexer
     * @param PhpVersion $phpVersion PHP version to target, defaults to latest supported. This
     *                               option is best-effort: Even if specified, parsing will generally assume the latest
     *                               supported version and only adjust behavior in minor ways, for example by omitting
     *                               errors in older versions and interpreting type hints as a name or identifier depending
     *                               on version.
     */
    public function __construct(Lexer $lexer, ?PhpVersion $phpVersion = null) {
        $this->lexer = $lexer;
        $this->phpVersion = $phpVersion ?? PhpVersion::getNewestSupported();

        $this->initReduceCallbacks();
        $this->phpTokenToSymbol = $this->createTokenMap();
        $this->dropTokens = array_fill_keys(
            [\T_WHITESPACE, \T_OPEN_TAG, \T_COMMENT, \T_DOC_COMMENT, \T_BAD_CHARACTER], true
        );
    }

    /**
     * Parses PHP code into a node tree.
     *
     * If a non-throwing error handler is used, the parser will continue parsing after an error
     * occurred and attempt to build a partial AST.
     *
     * @param string $code The source code to parse
     * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults
     *                                        to ErrorHandler\Throwing.
     *
     * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
     *                          the parser was unable to recover from an error).
     */
    public function parse(string $code, ?ErrorHandler $errorHandler = null): ?array {
        $this->errorHandler = $errorHandler ?: new ErrorHandler\Throwing();
        $this->createdArrays = new \SplObjectStorage();

        $this->tokens = $this->lexer->tokenize($code, $this->errorHandler);
        $result = $this->doParse();

        // Report errors for any empty elements used inside arrays. This is delayed until after the main parse,
        // because we don't know a priori whether a given array expression will be used in a destructuring context
        // or not.
        foreach ($this->createdArrays as $node) {
            foreach ($node->items as $item) {
                if ($item->value instanceof Expr\Error) {
                    $this->errorHandler->handleError(
                        new Error('Cannot use empty array elements in arrays', $item->getAttributes()));
                }
            }
        }

        // Clear out some of the interior state, so we don't hold onto unnecessary
        // memory between uses of the parser
        $this->tokenStartStack = [];
        $this->tokenEndStack = [];
        $this->semStack = [];
        $this->semValue = null;
        $this->createdArrays = null;

        if ($result !== null) {
            $traverser = new NodeTraverser(new CommentAnnotatingVisitor($this->tokens));
            $traverser->traverse($result);
        }

        return $result;
    }

    public function getTokens(): array {
        return $this->tokens;
    }

    /** @return Stmt[]|null */
    protected function doParse(): ?array {
        // We start off with no lookahead-token
        $symbol = self::SYMBOL_NONE;
        $tokenValue = null;
        $this->tokenPos = -1;

        // Keep stack of start and end attributes
        $this->tokenStartStack = [];
        $this->tokenEndStack = [0];

        // Start off in the initial state and keep a stack of previous states
        $state = 0;
        $stateStack = [$state];

        // Semantic value stack (contains values of tokens and semantic action results)
        $this->semStack = [];

        // Current position in the stack(s)
        $stackPos = 0;

        $this->errorState = 0;

        for (;;) {
            //$this->traceNewState($state, $symbol);

            if ($this->actionBase[$state] === 0) {
                $rule = $this->actionDefault[$state];
            } else {
                if ($symbol === self::SYMBOL_NONE) {
                    do {
                        $token = $this->tokens[++$this->tokenPos];
                        $tokenId = $token->id;
                    } while (isset($this->dropTokens[$tokenId]));

                    // Map the lexer token id to the internally used symbols.
                    $tokenValue = $token->text;
                    if (!isset($this->phpTokenToSymbol[$tokenId])) {
                        throw new \RangeException(sprintf(
                            'The lexer returned an invalid token (id=%d, value=%s)',
                            $tokenId, $tokenValue
                        ));
                    }
                    $symbol = $this->phpTokenToSymbol[$tokenId];

                    //$this->traceRead($symbol);
                }

                $idx = $this->actionBase[$state] + $symbol;
                if ((($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol)
                     || ($state < $this->YY2TBLSTATE
                         && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0
                         && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol))
                    && ($action = $this->action[$idx]) !== $this->defaultAction) {
                    /*
                     * >= numNonLeafStates: shift and reduce
                     * > 0: shift
                     * = 0: accept
                     * < 0: reduce
                     * = -YYUNEXPECTED: error
                     */
                    if ($action > 0) {
                        /* shift */
                        //$this->traceShift($symbol);

                        ++$stackPos;
                        $stateStack[$stackPos] = $state = $action;
                        $this->semStack[$stackPos] = $tokenValue;
                        $this->tokenStartStack[$stackPos] = $this->tokenPos;
                        $this->tokenEndStack[$stackPos] = $this->tokenPos;
                        $symbol = self::SYMBOL_NONE;

                        if ($this->errorState) {
                            --$this->errorState;
                        }

                        if ($action < $this->numNonLeafStates) {
                            continue;
                        }

                        /* $yyn >= numNonLeafStates means shift-and-reduce */
                        $rule = $action - $this->numNonLeafStates;
                    } else {
                        $rule = -$action;
                    }
                } else {
                    $rule = $this->actionDefault[$state];
                }
            }

            for (;;) {
                if ($rule === 0) {
                    /* accept */
                    //$this->traceAccept();
                    return $this->semValue;
                }
                if ($rule !== $this->unexpectedTokenRule) {
                    /* reduce */
                    //$this->traceReduce($rule);

                    $ruleLength = $this->ruleToLength[$rule];
                    try {
                        $callback = $this->reduceCallbacks[$rule];
                        if ($callback !== null) {
                            $callback($this, $stackPos);
                        } elseif ($ruleLength > 0) {
                            $this->semValue = $this->semStack[$stackPos - $ruleLength + 1];
                        }
                    } catch (Error $e) {
                        if (-1 === $e->getStartLine()) {
                            $e->setStartLine($this->tokens[$this->tokenPos]->line);
                        }

                        $this->emitError($e);
                        // Can't recover from this type of error
                        return null;
                    }

                    /* Goto - shift nonterminal */
                    $lastTokenEnd = $this->tokenEndStack[$stackPos];
                    $stackPos -= $ruleLength;
                    $nonTerminal = $this->ruleToNonTerminal[$rule];
                    $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos];
                    if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) {
                        $state = $this->goto[$idx];
                    } else {
                        $state = $this->gotoDefault[$nonTerminal];
                    }

                    ++$stackPos;
                    $stateStack[$stackPos]     = $state;
                    $this->semStack[$stackPos] = $this->semValue;
                    $this->tokenEndStack[$stackPos] = $lastTokenEnd;
                    if ($ruleLength === 0) {
                        // Empty productions use the start attributes of the lookahead token.
                        $this->tokenStartStack[$stackPos] = $this->tokenPos;
                    }
                } else {
                    /* error */
                    switch ($this->errorState) {
                        case 0:
                            $msg = $this->getErrorMessage($symbol, $state);
                            $this->emitError(new Error($msg, $this->getAttributesForToken($this->tokenPos)));
                            // Break missing intentionally
                            // no break
                        case 1:
                        case 2:
                            $this->errorState = 3;

                            // Pop until error-expecting state uncovered
                            while (!(
                                (($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0
                                    && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol)
                                || ($state < $this->YY2TBLSTATE
                                    && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0
                                    && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol)
                            ) || ($action = $this->action[$idx]) === $this->defaultAction) { // Not totally sure about this
                                if ($stackPos <= 0) {
                                    // Could not recover from error
                                    return null;
                                }
                                $state = $stateStack[--$stackPos];
                                //$this->tracePop($state);
                            }

                            //$this->traceShift($this->errorSymbol);
                            ++$stackPos;
                            $stateStack[$stackPos] = $state = $action;

                            // We treat the error symbol as being empty, so we reset the end attributes
                            // to the end attributes of the last non-error symbol
                            $this->tokenStartStack[$stackPos] = $this->tokenPos;
                            $this->tokenEndStack[$stackPos] = $this->tokenEndStack[$stackPos - 1];
                            break;

                        case 3:
                            if ($symbol === 0) {
                                // Reached EOF without recovering from error
                                return null;
                            }

                            //$this->traceDiscard($symbol);
                            $symbol = self::SYMBOL_NONE;
                            break 2;
                    }
                }

                if ($state < $this->numNonLeafStates) {
                    break;
                }

                /* >= numNonLeafStates means shift-and-reduce */
                $rule = $state - $this->numNonLeafStates;
            }
        }

        throw new \RuntimeException('Reached end of parser loop');
    }

    protected function emitError(Error $error): void {
        $this->errorHandler->handleError($error);
    }

    /**
     * Format error message including expected tokens.
     *
     * @param int $symbol Unexpected symbol
     * @param int $state State at time of error
     *
     * @return string Formatted error message
     */
    protected function getErrorMessage(int $symbol, int $state): string {
        $expectedString = '';
        if ($expected = $this->getExpectedTokens($state)) {
            $expectedString = ', expecting ' . implode(' or ', $expected);
        }

        return 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString;
    }

    /**
     * Get limited number of expected tokens in given state.
     *
     * @param int $state State
     *
     * @return string[] Expected tokens. If too many, an empty array is returned.
     */
    protected function getExpectedTokens(int $state): array {
        $expected = [];

        $base = $this->actionBase[$state];
        foreach ($this->symbolToName as $symbol => $name) {
            $idx = $base + $symbol;
            if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol
                || $state < $this->YY2TBLSTATE
                && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0
                && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol
            ) {
                if ($this->action[$idx] !== $this->unexpectedTokenRule
                    && $this->action[$idx] !== $this->defaultAction
                    && $symbol !== $this->errorSymbol
                ) {
                    if (count($expected) === 4) {
                        /* Too many expected tokens */
                        return [];
                    }

                    $expected[] = $name;
                }
            }
        }

        return $expected;
    }

    /**
     * Get attributes for a node with the given start and end token positions.
     *
     * @param int $tokenStartPos Token position the node starts at
     * @param int $tokenEndPos Token position the node ends at
     * @return array<string, mixed> Attributes
     */
    protected function getAttributes(int $tokenStartPos, int $tokenEndPos): array {
        $startToken = $this->tokens[$tokenStartPos];
        $afterEndToken = $this->tokens[$tokenEndPos + 1];
        return [
            'startLine' => $startToken->line,
            'startTokenPos' => $tokenStartPos,
            'startFilePos' => $startToken->pos,
            'endLine' => $afterEndToken->line,
            'endTokenPos' => $tokenEndPos,
            'endFilePos' => $afterEndToken->pos - 1,
        ];
    }

    /**
     * Get attributes for a single token at the given token position.
     *
     * @return array<string, mixed> Attributes
     */
    protected function getAttributesForToken(int $tokenPos): array {
        if ($tokenPos < \count($this->tokens) - 1) {
            return $this->getAttributes($tokenPos, $tokenPos);
        }

        // Get attributes for the sentinel token.
        $token = $this->tokens[$tokenPos];
        return [
            'startLine' => $token->line,
            'startTokenPos' => $tokenPos,
            'startFilePos' => $token->pos,
            'endLine' => $token->line,
            'endTokenPos' => $tokenPos,
            'endFilePos' => $token->pos,
        ];
    }

    /*
     * Tracing functions used for debugging the parser.
     */

    /*
    protected function traceNewState($state, $symbol): void {
        echo '% State ' . $state
            . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . "\n";
    }

    protected function traceRead($symbol): void {
        echo '% Reading ' . $this->symbolToName[$symbol] . "\n";
    }

    protected function traceShift($symbol): void {
        echo '% Shift ' . $this->symbolToName[$symbol] . "\n";
    }

    protected function traceAccept(): void {
        echo "% Accepted.\n";
    }

    protected function traceReduce($n): void {
        echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . "\n";
    }

    protected function tracePop($state): void {
        echo '% Recovering, uncovered state ' . $state . "\n";
    }

    protected function traceDiscard($symbol): void {
        echo '% Discard ' . $this->symbolToName[$symbol] . "\n";
    }
    */

    /*
     * Helper functions invoked by semantic actions
     */

    /**
     * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions.
     *
     * @param Node\Stmt[] $stmts
     * @return Node\Stmt[]
     */
    protected function handleNamespaces(array $stmts): array {
        $hasErrored = false;
        $style = $this->getNamespacingStyle($stmts);
        if (null === $style) {
            // not namespaced, nothing to do
            return $stmts;
        }
        if ('brace' === $style) {
            // For braced namespaces we only have to check that there are no invalid statements between the namespaces
            $afterFirstNamespace = false;
            foreach ($stmts as $stmt) {
                if ($stmt instanceof Node\Stmt\Namespace_) {
                    $afterFirstNamespace = true;
                } elseif (!$stmt instanceof Node\Stmt\HaltCompiler
                        && !$stmt instanceof Node\Stmt\Nop
                        && $afterFirstNamespace && !$hasErrored) {
                    $this->emitError(new Error(
                        'No code may exist outside of namespace {}', $stmt->getAttributes()));
                    $hasErrored = true; // Avoid one error for every statement
                }
            }
            return $stmts;
        } else {
            // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts
            $resultStmts = [];
            $targetStmts = &$resultStmts;
            $lastNs = null;
            foreach ($stmts as $stmt) {
                if ($stmt instanceof Node\Stmt\Namespace_) {
                    if ($lastNs !== null) {
                        $this->fixupNamespaceAttributes($lastNs);
                    }
                    if ($stmt->stmts === null) {
                        $stmt->stmts = [];
                        $targetStmts = &$stmt->stmts;
                        $resultStmts[] = $stmt;
                    } else {
                        // This handles the invalid case of mixed style namespaces
                        $resultStmts[] = $stmt;
                        $targetStmts = &$resultStmts;
                    }
                    $lastNs = $stmt;
                } elseif ($stmt instanceof Node\Stmt\HaltCompiler) {
                    // __halt_compiler() is not moved into the namespace
                    $resultStmts[] = $stmt;
                } else {
                    $targetStmts[] = $stmt;
                }
            }
            if ($lastNs !== null) {
                $this->fixupNamespaceAttributes($lastNs);
            }
            return $resultStmts;
        }
    }

    private function fixupNamespaceAttributes(Node\Stmt\Namespace_ $stmt): void {
        // We moved the statements into the namespace node, as such the end of the namespace node
        // needs to be extended to the end of the statements.
        if (empty($stmt->stmts)) {
            return;
        }

        // We only move the builtin end attributes here. This is the best we can do with the
        // knowledge we have.
        $endAttributes = ['endLine', 'endFilePos', 'endTokenPos'];
        $lastStmt = $stmt->stmts[count($stmt->stmts) - 1];
        foreach ($endAttributes as $endAttribute) {
            if ($lastStmt->hasAttribute($endAttribute)) {
                $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute));
            }
        }
    }

    /** @return array<string, mixed> */
    private function getNamespaceErrorAttributes(Namespace_ $node): array {
        $attrs = $node->getAttributes();
        // Adjust end attributes to only cover the "namespace" keyword, not the whole namespace.
        if (isset($attrs['startLine'])) {
            $attrs['endLine'] = $attrs['startLine'];
        }
        if (isset($attrs['startTokenPos'])) {
            $attrs['endTokenPos'] = $attrs['startTokenPos'];
        }
        if (isset($attrs['startFilePos'])) {
            $attrs['endFilePos'] = $attrs['startFilePos'] + \strlen('namespace') - 1;
        }
        return $attrs;
    }

    /**
     * Determine namespacing style (semicolon or brace)
     *
     * @param Node[] $stmts Top-level statements.
     *
     * @return null|string One of "semicolon", "brace" or null (no namespaces)
     */
    private function getNamespacingStyle(array $stmts): ?string {
        $style = null;
        $hasNotAllowedStmts = false;
        foreach ($stmts as $i => $stmt) {
            if ($stmt instanceof Node\Stmt\Namespace_) {
                $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace';
                if (null === $style) {
                    $style = $currentStyle;
                    if ($hasNotAllowedStmts) {
                        $this->emitError(new Error(
                            'Namespace declaration statement has to be the very first statement in the script',
                            $this->getNamespaceErrorAttributes($stmt)
                        ));
                    }
                } elseif ($style !== $currentStyle) {
                    $this->emitError(new Error(
                        'Cannot mix bracketed namespace declarations with unbracketed namespace declarations',
                        $this->getNamespaceErrorAttributes($stmt)
                    ));
                    // Treat like semicolon style for namespace normalization
                    return 'semicolon';
                }
                continue;
            }

            /* declare(), __halt_compiler() and nops can be used before a namespace declaration */
            if ($stmt instanceof Node\Stmt\Declare_
                || $stmt instanceof Node\Stmt\HaltCompiler
                || $stmt instanceof Node\Stmt\Nop) {
                continue;
            }

            /* There may be a hashbang line at the very start of the file */
            if ($i === 0 && $stmt instanceof Node\Stmt\InlineHTML && preg_match('/\A#!.*\r?\n\z/', $stmt->value)) {
                continue;
            }

            /* Everything else if forbidden before namespace declarations */
            $hasNotAllowedStmts = true;
        }
        return $style;
    }

    /** @return Name|Identifier */
    protected function handleBuiltinTypes(Name $name) {
        if (!$name->isUnqualified()) {
            return $name;
        }

        $lowerName = $name->toLowerString();
        if (!$this->phpVersion->supportsBuiltinType($lowerName)) {
            return $name;
        }

        return new Node\Identifier($lowerName, $name->getAttributes());
    }

    /**
     * Get combined start and end attributes at a stack location
     *
     * @param int $stackPos Stack location
     *
     * @return array<string, mixed> Combined start and end attributes
     */
    protected function getAttributesAt(int $stackPos): array {
        return $this->getAttributes($this->tokenStartStack[$stackPos], $this->tokenEndStack[$stackPos]);
    }

    protected function getFloatCastKind(string $cast): int {
        $cast = strtolower($cast);
        if (strpos($cast, 'float') !== false) {
            return Double::KIND_FLOAT;
        }

        if (strpos($cast, 'real') !== false) {
            return Double::KIND_REAL;
        }

        return Double::KIND_DOUBLE;
    }

    /** @param array<string, mixed> $attributes */
    protected function parseLNumber(string $str, array $attributes, bool $allowInvalidOctal = false): Int_ {
        try {
            return Int_::fromString($str, $attributes, $allowInvalidOctal);
        } catch (Error $error) {
            $this->emitError($error);
            // Use dummy value
            return new Int_(0, $attributes);
        }
    }

    /**
     * Parse a T_NUM_STRING token into either an integer or string node.
     *
     * @param string $str Number string
     * @param array<string, mixed> $attributes Attributes
     *
     * @return Int_|String_ Integer or string node.
     */
    protected function parseNumString(string $str, array $attributes) {
        if (!preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) {
            return new String_($str, $attributes);
        }

        $num = +$str;
        if (!is_int($num)) {
            return new String_($str, $attributes);
        }

        return new Int_($num, $attributes);
    }

    /** @param array<string, mixed> $attributes */
    protected function stripIndentation(
        string $string, int $indentLen, string $indentChar,
        bool $newlineAtStart, bool $newlineAtEnd, array $attributes
    ): string {
        if ($indentLen === 0) {
            return $string;
        }

        $start = $newlineAtStart ? '(?:(?<=\n)|\A)' : '(?<=\n)';
        $end = $newlineAtEnd ? '(?:(?=[\r\n])|\z)' : '(?=[\r\n])';
        $regex = '/' . $start . '([ \t]*)(' . $end . ')?/';
        return preg_replace_callback(
            $regex,
            function ($matches) use ($indentLen, $indentChar, $attributes) {
                $prefix = substr($matches[1], 0, $indentLen);
                if (false !== strpos($prefix, $indentChar === " " ? "\t" : " ")) {
                    $this->emitError(new Error(
                        'Invalid indentation - tabs and spaces cannot be mixed', $attributes
                    ));
                } elseif (strlen($prefix) < $indentLen && !isset($matches[2])) {
                    $this->emitError(new Error(
                        'Invalid body indentation level ' .
                        '(expecting an indentation level of at least ' . $indentLen . ')',
                        $attributes
                    ));
                }
                return substr($matches[0], strlen($prefix));
            },
            $string
        );
    }

    /**
     * @param string|(Expr|InterpolatedStringPart)[] $contents
     * @param array<string, mixed> $attributes
     * @param array<string, mixed> $endTokenAttributes
     */
    protected function parseDocString(
        string $startToken, $contents, string $endToken,
        array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape
    ): Expr {
        $kind = strpos($startToken, "'") === false
            ? String_::KIND_HEREDOC : String_::KIND_NOWDOC;

        $regex = '/\A[bB]?<<<[ \t]*[\'"]?([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)[\'"]?(?:\r\n|\n|\r)\z/';
        $result = preg_match($regex, $startToken, $matches);
        assert($result === 1);
        $label = $matches[1];

        $result = preg_match('/\A[ \t]*/', $endToken, $matches);
        assert($result === 1);
        $indentation = $matches[0];

        $attributes['kind'] = $kind;
        $attributes['docLabel'] = $label;
        $attributes['docIndentation'] = $indentation;

        $indentHasSpaces = false !== strpos($indentation, " ");
        $indentHasTabs = false !== strpos($indentation, "\t");
        if ($indentHasSpaces && $indentHasTabs) {
            $this->emitError(new Error(
                'Invalid indentation - tabs and spaces cannot be mixed',
                $endTokenAttributes
            ));

            // Proceed processing as if this doc string is not indented
            $indentation = '';
        }

        $indentLen = \strlen($indentation);
        $indentChar = $indentHasSpaces ? " " : "\t";

        if (\is_string($contents)) {
            if ($contents === '') {
                $attributes['rawValue'] = $contents;
                return new String_('', $attributes);
            }

            $contents = $this->stripIndentation(
                $contents, $indentLen, $indentChar, true, true, $attributes
            );
            $contents = preg_replace('~(\r\n|\n|\r)\z~', '', $contents);
            $attributes['rawValue'] = $contents;

            if ($kind === String_::KIND_HEREDOC) {
                $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape);
            }

            return new String_($contents, $attributes);
        } else {
            assert(count($contents) > 0);
            if (!$contents[0] instanceof Node\InterpolatedStringPart) {
                // If there is no leading encapsed string part, pretend there is an empty one
                $this->stripIndentation(
                    '', $indentLen, $indentChar, true, false, $contents[0]->getAttributes()
                );
            }

            $newContents = [];
            foreach ($contents as $i => $part) {
                if ($part instanceof Node\InterpolatedStringPart) {
                    $isLast = $i === \count($contents) - 1;
                    $part->value = $this->stripIndentation(
                        $part->value, $indentLen, $indentChar,
                        $i === 0, $isLast, $part->getAttributes()
                    );
                    if ($isLast) {
                        $part->value = preg_replace('~(\r\n|\n|\r)\z~', '', $part->value);
                    }
                    $part->setAttribute('rawValue', $part->value);
                    $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape);
                    if ('' === $part->value) {
                        continue;
                    }
                }
                $newContents[] = $part;
            }
            return new InterpolatedString($newContents, $attributes);
        }
    }

    protected function createCommentFromToken(Token $token, int $tokenPos): Comment {
        assert($token->id === \T_COMMENT || $token->id == \T_DOC_COMMENT);
        return \T_DOC_COMMENT === $token->id
            ? new Comment\Doc($token->text, $token->line, $token->pos, $tokenPos,
                $token->getEndLine(), $token->getEndPos() - 1, $tokenPos)
            : new Comment($token->text, $token->line, $token->pos, $tokenPos,
                $token->getEndLine(), $token->getEndPos() - 1, $tokenPos);
    }

    /**
     * Get last comment before the given token position, if any
     */
    protected function getCommentBeforeToken(int $tokenPos): ?Comment {
        while (--$tokenPos >= 0) {
            $token = $this->tokens[$tokenPos];
            if (!isset($this->dropTokens[$token->id])) {
                break;
            }

            if ($token->id === \T_COMMENT || $token->id === \T_DOC_COMMENT) {
                return $this->createCommentFromToken($token, $tokenPos);
            }
        }
        return null;
    }

    /**
     * Create a zero-length nop to capture preceding comments, if any.
     */
    protected function maybeCreateZeroLengthNop(int $tokenPos): ?Nop {
        $comment = $this->getCommentBeforeToken($tokenPos);
        if ($comment === null) {
            return null;
        }

        $commentEndLine = $comment->getEndLine();
        $commentEndFilePos = $comment->getEndFilePos();
        $commentEndTokenPos = $comment->getEndTokenPos();
        $attributes = [
            'startLine' => $commentEndLine,
            'endLine' => $commentEndLine,
            'startFilePos' => $commentEndFilePos + 1,
            'endFilePos' => $commentEndFilePos,
            'startTokenPos' => $commentEndTokenPos + 1,
            'endTokenPos' => $commentEndTokenPos,
        ];
        return new Nop($attributes);
    }

    protected function maybeCreateNop(int $tokenStartPos, int $tokenEndPos): ?Nop {
        if ($this->getCommentBeforeToken($tokenStartPos) === null) {
            return null;
        }
        return new Nop($this->getAttributes($tokenStartPos, $tokenEndPos));
    }

    protected function handleHaltCompiler(): string {
        // Prevent the lexer from returning any further tokens.
        $nextToken = $this->tokens[$this->tokenPos + 1];
        $this->tokenPos = \count($this->tokens) - 2;

        // Return text after __halt_compiler.
        return $nextToken->id === \T_INLINE_HTML ? $nextToken->text : '';
    }

    protected function inlineHtmlHasLeadingNewline(int $stackPos): bool {
        $tokenPos = $this->tokenStartStack[$stackPos];
        $token = $this->tokens[$tokenPos];
        assert($token->id == \T_INLINE_HTML);
        if ($tokenPos > 0) {
            $prevToken = $this->tokens[$tokenPos - 1];
            assert($prevToken->id == \T_CLOSE_TAG);
            return false !== strpos($prevToken->text, "\n")
                || false !== strpos($prevToken->text, "\r");
        }
        return true;
    }

    /**
     * @return array<string, mixed>
     */
    protected function createEmptyElemAttributes(int $tokenPos): array {
        return $this->getAttributesForToken($tokenPos);
    }

    protected function fixupArrayDestructuring(Array_ $node): Expr\List_ {
        $this->createdArrays->detach($node);
        return new Expr\List_(array_map(function (Node\ArrayItem $item) {
            if ($item->value instanceof Expr\Error) {
                // We used Error as a placeholder for empty elements, which are legal for destructuring.
                return null;
            }
            if ($item->value instanceof Array_) {
                return new Node\ArrayItem(
                    $this->fixupArrayDestructuring($item->value),
                    $item->key, $item->byRef, $item->getAttributes());
            }
            return $item;
        }, $node->items), ['kind' => Expr\List_::KIND_ARRAY] + $node->getAttributes());
    }

    protected function postprocessList(Expr\List_ $node): void {
        foreach ($node->items as $i => $item) {
            if ($item->value instanceof Expr\Error) {
                // We used Error as a placeholder for empty elements, which are legal for destructuring.
                $node->items[$i] = null;
            }
        }
    }

    /** @param ElseIf_|Else_ $node */
    protected function fixupAlternativeElse($node): void {
        // Make sure a trailing nop statement carrying comments is part of the node.
        $numStmts = \count($node->stmts);
        if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) {
            $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes();
            if (isset($nopAttrs['endLine'])) {
                $node->setAttribute('endLine', $nopAttrs['endLine']);
            }
            if (isset($nopAttrs['endFilePos'])) {
                $node->setAttribute('endFilePos', $nopAttrs['endFilePos']);
            }
            if (isset($nopAttrs['endTokenPos'])) {
                $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']);
            }
        }
    }

    protected function checkClassModifier(int $a, int $b, int $modifierPos): void {
        try {
            Modifiers::verifyClassModifier($a, $b);
        } catch (Error $error) {
            $error->setAttributes($this->getAttributesAt($modifierPos));
            $this->emitError($error);
        }
    }

    protected function checkModifier(int $a, int $b, int $modifierPos): void {
        // Jumping through some hoops here because verifyModifier() is also used elsewhere
        try {
            Modifiers::verifyModifier($a, $b);
        } catch (Error $error) {
            $error->setAttributes($this->getAttributesAt($modifierPos));
            $this->emitError($error);
        }
    }

    protected function checkParam(Param $node): void {
        if ($node->variadic && null !== $node->default) {
            $this->emitError(new Error(
                'Variadic parameter cannot have a default value',
                $node->default->getAttributes()
            ));
        }
    }

    protected function checkTryCatch(TryCatch $node): void {
        if (empty($node->catches) && null === $node->finally) {
            $this->emitError(new Error(
                'Cannot use try without catch or finally', $node->getAttributes()
            ));
        }
    }

    protected function checkNamespace(Namespace_ $node): void {
        if (null !== $node->stmts) {
            foreach ($node->stmts as $stmt) {
                if ($stmt instanceof Namespace_) {
                    $this->emitError(new Error(
                        'Namespace declarations cannot be nested', $stmt->getAttributes()
                    ));
                }
            }
        }
    }

    private function checkClassName(?Identifier $name, int $namePos): void {
        if (null !== $name && $name->isSpecialClassName()) {
            $this->emitError(new Error(
                sprintf('Cannot use \'%s\' as class name as it is reserved', $name),
                $this->getAttributesAt($namePos)
            ));
        }
    }

    /** @param Name[] $interfaces */
    private function checkImplementedInterfaces(array $interfaces): void {
        foreach ($interfaces as $interface) {
            if ($interface->isSpecialClassName()) {
                $this->emitError(new Error(
                    sprintf('Cannot use \'%s\' as interface name as it is reserved', $interface),
                    $interface->getAttributes()
                ));
            }
        }
    }

    protected function checkClass(Class_ $node, int $namePos): void {
        $this->checkClassName($node->name, $namePos);

        if ($node->extends && $node->extends->isSpecialClassName()) {
            $this->emitError(new Error(
                sprintf('Cannot use \'%s\' as class name as it is reserved', $node->extends),
                $node->extends->getAttributes()
            ));
        }

        $this->checkImplementedInterfaces($node->implements);
    }

    protected function checkInterface(Interface_ $node, int $namePos): void {
        $this->checkClassName($node->name, $namePos);
        $this->checkImplementedInterfaces($node->extends);
    }

    protected function checkEnum(Enum_ $node, int $namePos): void {
        $this->checkClassName($node->name, $namePos);
        $this->checkImplementedInterfaces($node->implements);
    }

    protected function checkClassMethod(ClassMethod $node, int $modifierPos): void {
        if ($node->flags & Modifiers::STATIC) {
            switch ($node->name->toLowerString()) {
                case '__construct':
                    $this->emitError(new Error(
                        sprintf('Constructor %s() cannot be static', $node->name),
                        $this->getAttributesAt($modifierPos)));
                    break;
                case '__destruct':
                    $this->emitError(new Error(
                        sprintf('Destructor %s() cannot be static', $node->name),
                        $this->getAttributesAt($modifierPos)));
                    break;
                case '__clone':
                    $this->emitError(new Error(
                        sprintf('Clone method %s() cannot be static', $node->name),
                        $this->getAttributesAt($modifierPos)));
                    break;
            }
        }

        if ($node->flags & Modifiers::READONLY) {
            $this->emitError(new Error(
                sprintf('Method %s() cannot be readonly', $node->name),
                $this->getAttributesAt($modifierPos)));
        }
    }

    protected function checkClassConst(ClassConst $node, int $modifierPos): void {
        if ($node->flags & Modifiers::STATIC) {
            $this->emitError(new Error(
                "Cannot use 'static' as constant modifier",
                $this->getAttributesAt($modifierPos)));
        }
        if ($node->flags & Modifiers::ABSTRACT) {
            $this->emitError(new Error(
                "Cannot use 'abstract' as constant modifier",
                $this->getAttributesAt($modifierPos)));
        }
        if ($node->flags & Modifiers::READONLY) {
            $this->emitError(new Error(
                "Cannot use 'readonly' as constant modifier",
                $this->getAttributesAt($modifierPos)));
        }
    }

    protected function checkProperty(Property $node, int $modifierPos): void {
        if ($node->flags & Modifiers::ABSTRACT) {
            $this->emitError(new Error('Properties cannot be declared abstract',
                $this->getAttributesAt($modifierPos)));
        }

        if ($node->flags & Modifiers::FINAL) {
            $this->emitError(new Error('Properties cannot be declared final',
                $this->getAttributesAt($modifierPos)));
        }
    }

    protected function checkUseUse(UseItem $node, int $namePos): void {
        if ($node->alias && $node->alias->isSpecialClassName()) {
            $this->emitError(new Error(
                sprintf(
                    'Cannot use %s as %s because \'%2$s\' is a special class name',
                    $node->name, $node->alias
                ),
                $this->getAttributesAt($namePos)
            ));
        }
    }

    /**
     * Creates the token map.
     *
     * The token map maps the PHP internal token identifiers
     * to the identifiers used by the Parser. Additionally it
     * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'.
     *
     * @return array<int, int> The token map
     */
    protected function createTokenMap(): array {
        $tokenMap = [];

        for ($i = 0; $i < 1000; ++$i) {
            if ($i < 256) {
                // Single-char tokens use an identity mapping.
                $tokenMap[$i] = $i;
            } elseif (\T_DOUBLE_COLON === $i) {
                // T_DOUBLE_COLON is equivalent to T_PAAMAYIM_NEKUDOTAYIM
                $tokenMap[$i] = static::T_PAAMAYIM_NEKUDOTAYIM;
            } elseif (\T_OPEN_TAG_WITH_ECHO === $i) {
                // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO
                $tokenMap[$i] = static::T_ECHO;
            } elseif (\T_CLOSE_TAG === $i) {
                // T_CLOSE_TAG is equivalent to ';'
                $tokenMap[$i] = ord(';');
            } elseif ('UNKNOWN' !== $name = token_name($i)) {
                if (defined($name = static::class . '::' . $name)) {
                    // Other tokens can be mapped directly
                    $tokenMap[$i] = constant($name);
                }
            }
        }

        // Assign tokens for which we define compatibility constants, as token_name() does not know them.
        $tokenMap[\T_FN] = static::T_FN;
        $tokenMap[\T_COALESCE_EQUAL] = static::T_COALESCE_EQUAL;
        $tokenMap[\T_NAME_QUALIFIED] = static::T_NAME_QUALIFIED;
        $tokenMap[\T_NAME_FULLY_QUALIFIED] = static::T_NAME_FULLY_QUALIFIED;
        $tokenMap[\T_NAME_RELATIVE] = static::T_NAME_RELATIVE;
        $tokenMap[\T_MATCH] = static::T_MATCH;
        $tokenMap[\T_NULLSAFE_OBJECT_OPERATOR] = static::T_NULLSAFE_OBJECT_OPERATOR;
        $tokenMap[\T_ATTRIBUTE] = static::T_ATTRIBUTE;
        $tokenMap[\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG] = static::T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG;
        $tokenMap[\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG] = static::T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG;
        $tokenMap[\T_ENUM] = static::T_ENUM;
        $tokenMap[\T_READONLY] = static::T_READONLY;

        // We have create a map from PHP token IDs to external symbol IDs.
        // Now map them to the internal symbol ID.
        $fullTokenMap = [];
        foreach ($tokenMap as $phpToken => $extSymbol) {
            $intSymbol = $this->tokenToSymbol[$extSymbol];
            if ($intSymbol === $this->invalidSymbol) {
                continue;
            }
            $fullTokenMap[$phpToken] = $intSymbol;
        }

        return $fullTokenMap;
    }
}
NodeTraverserInterface.php000064400000001126151520657540011673 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface NodeTraverserInterface {
    /**
     * Adds a visitor.
     *
     * @param NodeVisitor $visitor Visitor to add
     */
    public function addVisitor(NodeVisitor $visitor): void;

    /**
     * Removes an added visitor.
     */
    public function removeVisitor(NodeVisitor $visitor): void;

    /**
     * Traverses an array of nodes using the registered visitors.
     *
     * @param Node[] $nodes Array of nodes
     *
     * @return Node[] Traversed array of nodes
     */
    public function traverse(array $nodes): array;
}
NodeDumper.php000064400000023741151520657540007340 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\Include_;
use PhpParser\Node\Expr\List_;
use PhpParser\Node\Scalar\Int_;
use PhpParser\Node\Scalar\InterpolatedString;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\GroupUse;
use PhpParser\Node\Stmt\Use_;
use PhpParser\Node\UseItem;

class NodeDumper {
    private bool $dumpComments;
    private bool $dumpPositions;
    private bool $dumpOtherAttributes;
    private ?string $code;
    private string $res;
    private string $nl;

    private const IGNORE_ATTRIBUTES = [
        'comments' => true,
        'startLine' => true,
        'endLine' => true,
        'startFilePos' => true,
        'endFilePos' => true,
        'startTokenPos' => true,
        'endTokenPos' => true,
    ];

    /**
     * Constructs a NodeDumper.
     *
     * Supported options:
     *  * bool dumpComments: Whether comments should be dumped.
     *  * bool dumpPositions: Whether line/offset information should be dumped. To dump offset
     *                        information, the code needs to be passed to dump().
     *  * bool dumpOtherAttributes: Whether non-comment, non-position attributes should be dumped.
     *
     * @param array $options Options (see description)
     */
    public function __construct(array $options = []) {
        $this->dumpComments = !empty($options['dumpComments']);
        $this->dumpPositions = !empty($options['dumpPositions']);
        $this->dumpOtherAttributes = !empty($options['dumpOtherAttributes']);
    }

    /**
     * Dumps a node or array.
     *
     * @param array|Node $node Node or array to dump
     * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if
     *                          the dumpPositions option is enabled and the dumping of node offsets
     *                          is desired.
     *
     * @return string Dumped value
     */
    public function dump($node, ?string $code = null): string {
        $this->code = $code;
        $this->res = '';
        $this->nl = "\n";
        $this->dumpRecursive($node, false);
        return $this->res;
    }

    /** @param mixed $node */
    protected function dumpRecursive($node, bool $indent = true): void {
        if ($indent) {
            $this->nl .= "    ";
        }
        if ($node instanceof Node) {
            $this->res .= $node->getType();
            if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {
                $this->res .= $p;
            }
            $this->res .= '(';

            foreach ($node->getSubNodeNames() as $key) {
                $this->res .= "$this->nl    " . $key . ': ';

                $value = $node->$key;
                if (\is_int($value)) {
                    if ('flags' === $key || 'newModifier' === $key) {
                        $this->res .= $this->dumpFlags($value);
                        continue;
                    }
                    if ('type' === $key && $node instanceof Include_) {
                        $this->res .= $this->dumpIncludeType($value);
                        continue;
                    }
                    if ('type' === $key
                            && ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) {
                        $this->res .= $this->dumpUseType($value);
                        continue;
                    }
                }
                $this->dumpRecursive($value);
            }

            if ($this->dumpComments && $comments = $node->getComments()) {
                $this->res .= "$this->nl    comments: ";
                $this->dumpRecursive($comments);
            }

            if ($this->dumpOtherAttributes) {
                foreach ($node->getAttributes() as $key => $value) {
                    if (isset(self::IGNORE_ATTRIBUTES[$key])) {
                        continue;
                    }

                    $this->res .= "$this->nl    $key: ";
                    if (\is_int($value)) {
                        if ('kind' === $key) {
                            if ($node instanceof Int_) {
                                $this->res .= $this->dumpIntKind($value);
                                continue;
                            }
                            if ($node instanceof String_ || $node instanceof InterpolatedString) {
                                $this->res .= $this->dumpStringKind($value);
                                continue;
                            }
                            if ($node instanceof Array_) {
                                $this->res .= $this->dumpArrayKind($value);
                                continue;
                            }
                            if ($node instanceof List_) {
                                $this->res .= $this->dumpListKind($value);
                                continue;
                            }
                        }
                    }
                    $this->dumpRecursive($value);
                }
            }
            $this->res .= "$this->nl)";
        } elseif (\is_array($node)) {
            $this->res .= 'array(';
            foreach ($node as $key => $value) {
                $this->res .= "$this->nl    " . $key . ': ';
                $this->dumpRecursive($value);
            }
            $this->res .= "$this->nl)";
        } elseif ($node instanceof Comment) {
            $this->res .= \str_replace("\n", $this->nl, $node->getReformattedText());
        } elseif (\is_string($node)) {
            $this->res .= \str_replace("\n", $this->nl, (string)$node);
        } elseif (\is_int($node) || \is_float($node)) {
            $this->res .= $node;
        } elseif (null === $node) {
            $this->res .= 'null';
        } elseif (false === $node) {
            $this->res .= 'false';
        } elseif (true === $node) {
            $this->res .= 'true';
        } else {
            throw new \InvalidArgumentException('Can only dump nodes and arrays.');
        }
        if ($indent) {
            $this->nl = \substr($this->nl, 0, -4);
        }
    }

    protected function dumpFlags(int $flags): string {
        $strs = [];
        if ($flags & Modifiers::PUBLIC) {
            $strs[] = 'PUBLIC';
        }
        if ($flags & Modifiers::PROTECTED) {
            $strs[] = 'PROTECTED';
        }
        if ($flags & Modifiers::PRIVATE) {
            $strs[] = 'PRIVATE';
        }
        if ($flags & Modifiers::ABSTRACT) {
            $strs[] = 'ABSTRACT';
        }
        if ($flags & Modifiers::STATIC) {
            $strs[] = 'STATIC';
        }
        if ($flags & Modifiers::FINAL) {
            $strs[] = 'FINAL';
        }
        if ($flags & Modifiers::READONLY) {
            $strs[] = 'READONLY';
        }

        if ($strs) {
            return implode(' | ', $strs) . ' (' . $flags . ')';
        } else {
            return (string) $flags;
        }
    }

    /** @param array<int, string> $map */
    private function dumpEnum(int $value, array $map): string {
        if (!isset($map[$value])) {
            return (string) $value;
        }
        return $map[$value] . ' (' . $value . ')';
    }

    private function dumpIncludeType(int $type): string {
        return $this->dumpEnum($type, [
            Include_::TYPE_INCLUDE      => 'TYPE_INCLUDE',
            Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',
            Include_::TYPE_REQUIRE      => 'TYPE_REQUIRE',
            Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE',
        ]);
    }

    private function dumpUseType(int $type): string {
        return $this->dumpEnum($type, [
            Use_::TYPE_UNKNOWN  => 'TYPE_UNKNOWN',
            Use_::TYPE_NORMAL   => 'TYPE_NORMAL',
            Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',
            Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',
        ]);
    }

    private function dumpIntKind(int $kind): string {
        return $this->dumpEnum($kind, [
            Int_::KIND_BIN => 'KIND_BIN',
            Int_::KIND_OCT => 'KIND_OCT',
            Int_::KIND_DEC => 'KIND_DEC',
            Int_::KIND_HEX => 'KIND_HEX',
        ]);
    }

    private function dumpStringKind(int $kind): string {
        return $this->dumpEnum($kind, [
            String_::KIND_SINGLE_QUOTED => 'KIND_SINGLE_QUOTED',
            String_::KIND_DOUBLE_QUOTED => 'KIND_DOUBLE_QUOTED',
            String_::KIND_HEREDOC => 'KIND_HEREDOC',
            String_::KIND_NOWDOC => 'KIND_NOWDOC',
        ]);
    }

    private function dumpArrayKind(int $kind): string {
        return $this->dumpEnum($kind, [
            Array_::KIND_LONG => 'KIND_LONG',
            Array_::KIND_SHORT => 'KIND_SHORT',
        ]);
    }

    private function dumpListKind(int $kind): string {
        return $this->dumpEnum($kind, [
            List_::KIND_LIST => 'KIND_LIST',
            List_::KIND_ARRAY => 'KIND_ARRAY',
        ]);
    }

    /**
     * Dump node position, if possible.
     *
     * @param Node $node Node for which to dump position
     *
     * @return string|null Dump of position, or null if position information not available
     */
    protected function dumpPosition(Node $node): ?string {
        if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {
            return null;
        }

        $start = $node->getStartLine();
        $end = $node->getEndLine();
        if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')
            && null !== $this->code
        ) {
            $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos());
            $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos());
        }
        return "[$start - $end]";
    }

    // Copied from Error class
    private function toColumn(string $code, int $pos): int {
        if ($pos > strlen($code)) {
            throw new \RuntimeException('Invalid position information');
        }

        $lineStartPos = strrpos($code, "\n", $pos - strlen($code));
        if (false === $lineStartPos) {
            $lineStartPos = -1;
        }

        return $pos - $lineStartPos;
    }
}
PrettyPrinterAbstract.php000064400000210755151520657540011620 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Internal\DiffElem;
use PhpParser\Internal\Differ;
use PhpParser\Internal\PrintableNewAnonClassNode;
use PhpParser\Internal\TokenStream;
use PhpParser\Node\AttributeGroup;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\IntersectionType;
use PhpParser\Node\MatchArm;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;
use PhpParser\Node\UnionType;

abstract class PrettyPrinterAbstract implements PrettyPrinter {
    protected const FIXUP_PREC_LEFT = 0; // LHS operand affected by precedence
    protected const FIXUP_PREC_RIGHT = 1; // RHS operand affected by precedence
    protected const FIXUP_PREC_UNARY = 2; // Only operand affected by precedence
    protected const FIXUP_CALL_LHS = 3; // LHS of call
    protected const FIXUP_DEREF_LHS = 4; // LHS of dereferencing operation
    protected const FIXUP_STATIC_DEREF_LHS = 5; // LHS of static dereferencing operation
    protected const FIXUP_BRACED_NAME  = 6; // Name operand that may require bracing
    protected const FIXUP_VAR_BRACED_NAME = 7; // Name operand that may require ${} bracing
    protected const FIXUP_ENCAPSED = 8; // Encapsed string part
    protected const FIXUP_NEW = 9; // New/instanceof operand

    protected const MAX_PRECEDENCE = 1000;

    /** @var array<class-string, array{int, int, int}> */
    protected array $precedenceMap = [
        // [precedence, precedenceLHS, precedenceRHS]
        // Where the latter two are the precedences to use for the LHS and RHS of a binary operator,
        // where 1 is added to one of the sides depending on associativity. This information is not
        // used for unary operators and set to -1.
        Expr\Clone_::class             => [-10,   0,   1],
        BinaryOp\Pow::class            => [  0,   0,   1],
        Expr\BitwiseNot::class         => [ 10,  -1,  -1],
        Expr\UnaryPlus::class          => [ 10,  -1,  -1],
        Expr\UnaryMinus::class         => [ 10,  -1,  -1],
        Cast\Int_::class               => [ 10,  -1,  -1],
        Cast\Double::class             => [ 10,  -1,  -1],
        Cast\String_::class            => [ 10,  -1,  -1],
        Cast\Array_::class             => [ 10,  -1,  -1],
        Cast\Object_::class            => [ 10,  -1,  -1],
        Cast\Bool_::class              => [ 10,  -1,  -1],
        Cast\Unset_::class             => [ 10,  -1,  -1],
        Expr\ErrorSuppress::class      => [ 10,  -1,  -1],
        Expr\Instanceof_::class        => [ 20,  -1,  -1],
        Expr\BooleanNot::class         => [ 30,  -1,  -1],
        BinaryOp\Mul::class            => [ 40,  41,  40],
        BinaryOp\Div::class            => [ 40,  41,  40],
        BinaryOp\Mod::class            => [ 40,  41,  40],
        BinaryOp\Plus::class           => [ 50,  51,  50],
        BinaryOp\Minus::class          => [ 50,  51,  50],
        BinaryOp\Concat::class         => [ 50,  51,  50],
        BinaryOp\ShiftLeft::class      => [ 60,  61,  60],
        BinaryOp\ShiftRight::class     => [ 60,  61,  60],
        BinaryOp\Smaller::class        => [ 70,  70,  70],
        BinaryOp\SmallerOrEqual::class => [ 70,  70,  70],
        BinaryOp\Greater::class        => [ 70,  70,  70],
        BinaryOp\GreaterOrEqual::class => [ 70,  70,  70],
        BinaryOp\Equal::class          => [ 80,  80,  80],
        BinaryOp\NotEqual::class       => [ 80,  80,  80],
        BinaryOp\Identical::class      => [ 80,  80,  80],
        BinaryOp\NotIdentical::class   => [ 80,  80,  80],
        BinaryOp\Spaceship::class      => [ 80,  80,  80],
        BinaryOp\BitwiseAnd::class     => [ 90,  91,  90],
        BinaryOp\BitwiseXor::class     => [100, 101, 100],
        BinaryOp\BitwiseOr::class      => [110, 111, 110],
        BinaryOp\BooleanAnd::class     => [120, 121, 120],
        BinaryOp\BooleanOr::class      => [130, 131, 130],
        BinaryOp\Coalesce::class       => [140, 140, 141],
        Expr\Ternary::class            => [150,  -1,  -1],
        Expr\Assign::class             => [160,  -1,  -1],
        Expr\AssignRef::class          => [160,  -1,  -1],
        AssignOp\Plus::class           => [160,  -1,  -1],
        AssignOp\Minus::class          => [160,  -1,  -1],
        AssignOp\Mul::class            => [160,  -1,  -1],
        AssignOp\Div::class            => [160,  -1,  -1],
        AssignOp\Concat::class         => [160,  -1,  -1],
        AssignOp\Mod::class            => [160,  -1,  -1],
        AssignOp\BitwiseAnd::class     => [160,  -1,  -1],
        AssignOp\BitwiseOr::class      => [160,  -1,  -1],
        AssignOp\BitwiseXor::class     => [160,  -1,  -1],
        AssignOp\ShiftLeft::class      => [160,  -1,  -1],
        AssignOp\ShiftRight::class     => [160,  -1,  -1],
        AssignOp\Pow::class            => [160,  -1,  -1],
        AssignOp\Coalesce::class       => [160,  -1,  -1],
        Expr\YieldFrom::class          => [170,  -1,  -1],
        Expr\Yield_::class             => [175,  -1,  -1],
        Expr\Print_::class             => [180,  -1,  -1],
        BinaryOp\LogicalAnd::class     => [190, 191, 190],
        BinaryOp\LogicalXor::class     => [200, 201, 200],
        BinaryOp\LogicalOr::class      => [210, 211, 210],
        Expr\Include_::class           => [220,  -1,  -1],
        Expr\ArrowFunction::class      => [230,  -1,  -1],
        Expr\Throw_::class             => [240,  -1,  -1],
    ];

    /** @var int Current indentation level. */
    protected int $indentLevel;
    /** @var string Newline style. Does not include current indentation. */
    protected string $newline;
    /** @var string Newline including current indentation. */
    protected string $nl;
    /** @var string|null Token placed at end of doc string to ensure it is followed by a newline.
     *                   Null if flexible doc strings are used. */
    protected ?string $docStringEndToken;
    /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */
    protected bool $canUseSemicolonNamespaces;
    /** @var bool Whether to use short array syntax if the node specifies no preference */
    protected bool $shortArraySyntax;
    /** @var PhpVersion PHP version to target */
    protected PhpVersion $phpVersion;

    /** @var TokenStream|null Original tokens for use in format-preserving pretty print */
    protected ?TokenStream $origTokens;
    /** @var Internal\Differ<Node> Differ for node lists */
    protected Differ $nodeListDiffer;
    /** @var array<string, bool> Map determining whether a certain character is a label character */
    protected array $labelCharMap;
    /**
     * @var array<string, array<string, int>> Map from token classes and subnode names to FIXUP_* constants.
     *                                        This is used during format-preserving prints to place additional parens/braces if necessary.
     */
    protected array $fixupMap;
    /**
     * @var array<string, array{left?: int|string, right?: int|string}> Map from "{$node->getType()}->{$subNode}"
     *                                                                  to ['left' => $l, 'right' => $r], where $l and $r specify the token type that needs to be stripped
     *                                                                  when removing this node.
     */
    protected array $removalMap;
    /**
     * @var array<string, array{int|string|null, bool, string|null, string|null}> Map from
     *                                                                            "{$node->getType()}->{$subNode}" to [$find, $beforeToken, $extraLeft, $extraRight].
     *                                                                            $find is an optional token after which the insertion occurs. $extraLeft/Right
     *                                                                            are optionally added before/after the main insertions.
     */
    protected array $insertionMap;
    /**
     * @var array<string, string> Map From "{$class}->{$subNode}" to string that should be inserted
     *                            between elements of this list subnode.
     */
    protected array $listInsertionMap;

    /**
     * @var array<string, array{int|string|null, string, string}>
     */
    protected array $emptyListInsertionMap;
    /** @var array<string, array{string, int}> Map from "{$class}->{$subNode}" to [$printFn, $token]
     *       where $printFn is the function to print the modifiers and $token is the token before which
     *       the modifiers should be reprinted. */
    protected array $modifierChangeMap;

    /**
     * Creates a pretty printer instance using the given options.
     *
     * Supported options:
     *  * PhpVersion $phpVersion: The PHP version to target (default to PHP 7.4). This option
     *                            controls compatibility of the generated code with older PHP
     *                            versions in cases where a simple stylistic choice exists (e.g.
     *                            array() vs []). It is safe to pretty-print an AST for a newer
     *                            PHP version while specifying an older target (but the result will
     *                            of course not be compatible with the older version in that case).
     *  * string $newline:        The newline style to use. Should be "\n" (default) or "\r\n".
     *  * bool $shortArraySyntax: Whether to use [] instead of array() as the default array
     *                            syntax, if the node does not specify a format. Defaults to whether
     *                            the phpVersion support short array syntax.
     *
     * @param array{
     *     phpVersion?: PhpVersion, newline?: string, shortArraySyntax?: bool
     * } $options Dictionary of formatting options
     */
    public function __construct(array $options = []) {
        $this->phpVersion = $options['phpVersion'] ?? PhpVersion::fromComponents(7, 4);

        $this->newline = $options['newline'] ?? "\n";
        if ($this->newline !== "\n" && $this->newline != "\r\n") {
            throw new \LogicException('Option "newline" must be one of "\n" or "\r\n"');
        }

        $this->shortArraySyntax =
            $options['shortArraySyntax'] ?? $this->phpVersion->supportsShortArraySyntax();
        $this->docStringEndToken =
            $this->phpVersion->supportsFlexibleHeredoc() ? null : '_DOC_STRING_END_' . mt_rand();
    }

    /**
     * Reset pretty printing state.
     */
    protected function resetState(): void {
        $this->indentLevel = 0;
        $this->nl = $this->newline;
        $this->origTokens = null;
    }

    /**
     * Set indentation level
     *
     * @param int $level Level in number of spaces
     */
    protected function setIndentLevel(int $level): void {
        $this->indentLevel = $level;
        $this->nl = $this->newline . \str_repeat(' ', $level);
    }

    /**
     * Increase indentation level.
     */
    protected function indent(): void {
        $this->indentLevel += 4;
        $this->nl .= '    ';
    }

    /**
     * Decrease indentation level.
     */
    protected function outdent(): void {
        assert($this->indentLevel >= 4);
        $this->indentLevel -= 4;
        $this->nl = $this->newline . str_repeat(' ', $this->indentLevel);
    }

    /**
     * Pretty prints an array of statements.
     *
     * @param Node[] $stmts Array of statements
     *
     * @return string Pretty printed statements
     */
    public function prettyPrint(array $stmts): string {
        $this->resetState();
        $this->preprocessNodes($stmts);

        return ltrim($this->handleMagicTokens($this->pStmts($stmts, false)));
    }

    /**
     * Pretty prints an expression.
     *
     * @param Expr $node Expression node
     *
     * @return string Pretty printed node
     */
    public function prettyPrintExpr(Expr $node): string {
        $this->resetState();
        return $this->handleMagicTokens($this->p($node));
    }

    /**
     * Pretty prints a file of statements (includes the opening <?php tag if it is required).
     *
     * @param Node[] $stmts Array of statements
     *
     * @return string Pretty printed statements
     */
    public function prettyPrintFile(array $stmts): string {
        if (!$stmts) {
            return "<?php" . $this->newline . $this->newline;
        }

        $p = "<?php" . $this->newline . $this->newline . $this->prettyPrint($stmts);

        if ($stmts[0] instanceof Stmt\InlineHTML) {
            $p = preg_replace('/^<\?php\s+\?>\r?\n?/', '', $p);
        }
        if ($stmts[count($stmts) - 1] instanceof Stmt\InlineHTML) {
            $p = preg_replace('/<\?php$/', '', rtrim($p));
        }

        return $p;
    }

    /**
     * Preprocesses the top-level nodes to initialize pretty printer state.
     *
     * @param Node[] $nodes Array of nodes
     */
    protected function preprocessNodes(array $nodes): void {
        /* We can use semicolon-namespaces unless there is a global namespace declaration */
        $this->canUseSemicolonNamespaces = true;
        foreach ($nodes as $node) {
            if ($node instanceof Stmt\Namespace_ && null === $node->name) {
                $this->canUseSemicolonNamespaces = false;
                break;
            }
        }
    }

    /**
     * Handles (and removes) doc-string-end tokens.
     */
    protected function handleMagicTokens(string $str): string {
        if ($this->docStringEndToken !== null) {
            // Replace doc-string-end tokens with nothing or a newline
            $str = str_replace(
                $this->docStringEndToken . ';' . $this->newline,
                ';' . $this->newline,
                $str);
            $str = str_replace($this->docStringEndToken, $this->newline, $str);
        }

        return $str;
    }

    /**
     * Pretty prints an array of nodes (statements) and indents them optionally.
     *
     * @param Node[] $nodes Array of nodes
     * @param bool $indent Whether to indent the printed nodes
     *
     * @return string Pretty printed statements
     */
    protected function pStmts(array $nodes, bool $indent = true): string {
        if ($indent) {
            $this->indent();
        }

        $result = '';
        foreach ($nodes as $node) {
            $comments = $node->getComments();
            if ($comments) {
                $result .= $this->nl . $this->pComments($comments);
                if ($node instanceof Stmt\Nop) {
                    continue;
                }
            }

            $result .= $this->nl . $this->p($node);
        }

        if ($indent) {
            $this->outdent();
        }

        return $result;
    }

    /**
     * Pretty-print an infix operation while taking precedence into account.
     *
     * @param string $class Node class of operator
     * @param Node $leftNode Left-hand side node
     * @param string $operatorString String representation of the operator
     * @param Node $rightNode Right-hand side node
     * @param int $precedence Precedence of parent operator
     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
     *
     * @return string Pretty printed infix operation
     */
    protected function pInfixOp(
        string $class, Node $leftNode, string $operatorString, Node $rightNode,
        int $precedence, int $lhsPrecedence
    ): string {
        list($opPrecedence, $newPrecedenceLHS, $newPrecedenceRHS) = $this->precedenceMap[$class];
        $prefix = '';
        $suffix = '';
        if ($opPrecedence >= $precedence) {
            $prefix = '(';
            $suffix = ')';
            $lhsPrecedence = self::MAX_PRECEDENCE;
        }
        return $prefix . $this->p($leftNode, $newPrecedenceLHS, $newPrecedenceLHS)
            . $operatorString . $this->p($rightNode, $newPrecedenceRHS, $lhsPrecedence) . $suffix;
    }

    /**
     * Pretty-print a prefix operation while taking precedence into account.
     *
     * @param string $class Node class of operator
     * @param string $operatorString String representation of the operator
     * @param Node $node Node
     * @param int $precedence Precedence of parent operator
     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
     *
     * @return string Pretty printed prefix operation
     */
    protected function pPrefixOp(string $class, string $operatorString, Node $node, int $precedence, int $lhsPrecedence): string {
        $opPrecedence = $this->precedenceMap[$class][0];
        $prefix = '';
        $suffix = '';
        if ($opPrecedence >= $lhsPrecedence) {
            $prefix = '(';
            $suffix = ')';
            $lhsPrecedence = self::MAX_PRECEDENCE;
        }
        $printedArg = $this->p($node, $opPrecedence, $lhsPrecedence);
        if (($operatorString === '+' && $printedArg[0] === '+') ||
            ($operatorString === '-' && $printedArg[0] === '-')
        ) {
            // Avoid printing +(+$a) as ++$a and similar.
            $printedArg = '(' . $printedArg . ')';
        }
        return $prefix . $operatorString . $printedArg . $suffix;
    }

    /**
     * Pretty-print a postfix operation while taking precedence into account.
     *
     * @param string $class Node class of operator
     * @param string $operatorString String representation of the operator
     * @param Node $node Node
     * @param int $precedence Precedence of parent operator
     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
     *
     * @return string Pretty printed postfix operation
     */
    protected function pPostfixOp(string $class, Node $node, string $operatorString, int $precedence, int $lhsPrecedence): string {
        $opPrecedence = $this->precedenceMap[$class][0];
        $prefix = '';
        $suffix = '';
        if ($opPrecedence >= $precedence) {
            $prefix = '(';
            $suffix = ')';
            $lhsPrecedence = self::MAX_PRECEDENCE;
        }
        if ($opPrecedence < $lhsPrecedence) {
            $lhsPrecedence = $opPrecedence;
        }
        return $prefix . $this->p($node, $opPrecedence, $lhsPrecedence) . $operatorString . $suffix;
    }

    /**
     * Pretty prints an array of nodes and implodes the printed values.
     *
     * @param Node[] $nodes Array of Nodes to be printed
     * @param string $glue Character to implode with
     *
     * @return string Imploded pretty printed nodes> $pre
     */
    protected function pImplode(array $nodes, string $glue = ''): string {
        $pNodes = [];
        foreach ($nodes as $node) {
            if (null === $node) {
                $pNodes[] = '';
            } else {
                $pNodes[] = $this->p($node);
            }
        }

        return implode($glue, $pNodes);
    }

    /**
     * Pretty prints an array of nodes and implodes the printed values with commas.
     *
     * @param Node[] $nodes Array of Nodes to be printed
     *
     * @return string Comma separated pretty printed nodes
     */
    protected function pCommaSeparated(array $nodes): string {
        return $this->pImplode($nodes, ', ');
    }

    /**
     * Pretty prints a comma-separated list of nodes in multiline style, including comments.
     *
     * The result includes a leading newline and one level of indentation (same as pStmts).
     *
     * @param Node[] $nodes Array of Nodes to be printed
     * @param bool $trailingComma Whether to use a trailing comma
     *
     * @return string Comma separated pretty printed nodes in multiline style
     */
    protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma): string {
        $this->indent();

        $result = '';
        $lastIdx = count($nodes) - 1;
        foreach ($nodes as $idx => $node) {
            if ($node !== null) {
                $comments = $node->getComments();
                if ($comments) {
                    $result .= $this->nl . $this->pComments($comments);
                }

                $result .= $this->nl . $this->p($node);
            } else {
                $result .= $this->nl;
            }
            if ($trailingComma || $idx !== $lastIdx) {
                $result .= ',';
            }
        }

        $this->outdent();
        return $result;
    }

    /**
     * Prints reformatted text of the passed comments.
     *
     * @param Comment[] $comments List of comments
     *
     * @return string Reformatted text of comments
     */
    protected function pComments(array $comments): string {
        $formattedComments = [];

        foreach ($comments as $comment) {
            $formattedComments[] = str_replace("\n", $this->nl, $comment->getReformattedText());
        }

        return implode($this->nl, $formattedComments);
    }

    /**
     * Perform a format-preserving pretty print of an AST.
     *
     * The format preservation is best effort. For some changes to the AST the formatting will not
     * be preserved (at least not locally).
     *
     * In order to use this method a number of prerequisites must be satisfied:
     *  * The startTokenPos and endTokenPos attributes in the lexer must be enabled.
     *  * The CloningVisitor must be run on the AST prior to modification.
     *  * The original tokens must be provided, using the getTokens() method on the lexer.
     *
     * @param Node[] $stmts Modified AST with links to original AST
     * @param Node[] $origStmts Original AST with token offset information
     * @param Token[] $origTokens Tokens of the original code
     */
    public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string {
        $this->initializeNodeListDiffer();
        $this->initializeLabelCharMap();
        $this->initializeFixupMap();
        $this->initializeRemovalMap();
        $this->initializeInsertionMap();
        $this->initializeListInsertionMap();
        $this->initializeEmptyListInsertionMap();
        $this->initializeModifierChangeMap();

        $this->resetState();
        $this->origTokens = new TokenStream($origTokens);

        $this->preprocessNodes($stmts);

        $pos = 0;
        $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null);
        if (null !== $result) {
            $result .= $this->origTokens->getTokenCode($pos, count($origTokens) - 1, 0);
        } else {
            // Fallback
            // TODO Add <?php properly
            $result = "<?php" . $this->newline . $this->pStmts($stmts, false);
        }

        return $this->handleMagicTokens($result);
    }

    protected function pFallback(Node $node, int $precedence, int $lhsPrecedence): string {
        return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);
    }

    /**
     * Pretty prints a node.
     *
     * This method also handles formatting preservation for nodes.
     *
     * @param Node $node Node to be pretty printed
     * @param int $precedence Precedence of parent operator
     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator
     * @param bool $parentFormatPreserved Whether parent node has preserved formatting
     *
     * @return string Pretty printed node
     */
    protected function p(
        Node $node, int $precedence = self::MAX_PRECEDENCE, int $lhsPrecedence = self::MAX_PRECEDENCE,
        bool $parentFormatPreserved = false
    ): string {
        // No orig tokens means this is a normal pretty print without preservation of formatting
        if (!$this->origTokens) {
            return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);
        }

        /** @var Node|null $origNode */
        $origNode = $node->getAttribute('origNode');
        if (null === $origNode) {
            return $this->pFallback($node, $precedence, $lhsPrecedence);
        }

        $class = \get_class($node);
        \assert($class === \get_class($origNode));

        $startPos = $origNode->getStartTokenPos();
        $endPos = $origNode->getEndTokenPos();
        \assert($startPos >= 0 && $endPos >= 0);

        $fallbackNode = $node;
        if ($node instanceof Expr\New_ && $node->class instanceof Stmt\Class_) {
            // Normalize node structure of anonymous classes
            assert($origNode instanceof Expr\New_);
            $node = PrintableNewAnonClassNode::fromNewNode($node);
            $origNode = PrintableNewAnonClassNode::fromNewNode($origNode);
            $class = PrintableNewAnonClassNode::class;
        }

        // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting
        // is not preserved, then we need to use the fallback code to make sure the tags are
        // printed.
        if ($node instanceof Stmt\InlineHTML && !$parentFormatPreserved) {
            return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
        }

        $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos);

        $type = $node->getType();
        $fixupInfo = $this->fixupMap[$class] ?? null;

        $result = '';
        $pos = $startPos;
        foreach ($node->getSubNodeNames() as $subNodeName) {
            $subNode = $node->$subNodeName;
            $origSubNode = $origNode->$subNodeName;

            if ((!$subNode instanceof Node && $subNode !== null)
                || (!$origSubNode instanceof Node && $origSubNode !== null)
            ) {
                if ($subNode === $origSubNode) {
                    // Unchanged, can reuse old code
                    continue;
                }

                if (is_array($subNode) && is_array($origSubNode)) {
                    // Array subnode changed, we might be able to reconstruct it
                    $listResult = $this->pArray(
                        $subNode, $origSubNode, $pos, $indentAdjustment, $class, $subNodeName,
                        $fixupInfo[$subNodeName] ?? null
                    );
                    if (null === $listResult) {
                        return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
                    }

                    $result .= $listResult;
                    continue;
                }

                // Check if this is a modifier change
                $key = $class . '->' . $subNodeName;
                if (!isset($this->modifierChangeMap[$key])) {
                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
                }

                [$printFn, $findToken] = $this->modifierChangeMap[$key];
                $result .= $this->$printFn($subNode);
                $pos = $this->origTokens->findRight($pos, $findToken);
                continue;
            }

            $extraLeft = '';
            $extraRight = '';
            if ($origSubNode !== null) {
                $subStartPos = $origSubNode->getStartTokenPos();
                $subEndPos = $origSubNode->getEndTokenPos();
                \assert($subStartPos >= 0 && $subEndPos >= 0);
            } else {
                if ($subNode === null) {
                    // Both null, nothing to do
                    continue;
                }

                // A node has been inserted, check if we have insertion information for it
                $key = $type . '->' . $subNodeName;
                if (!isset($this->insertionMap[$key])) {
                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
                }

                list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key];
                if (null !== $findToken) {
                    $subStartPos = $this->origTokens->findRight($pos, $findToken)
                        + (int) !$beforeToken;
                } else {
                    $subStartPos = $pos;
                }

                if (null === $extraLeft && null !== $extraRight) {
                    // If inserting on the right only, skipping whitespace looks better
                    $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos);
                }
                $subEndPos = $subStartPos - 1;
            }

            if (null === $subNode) {
                // A node has been removed, check if we have removal information for it
                $key = $type . '->' . $subNodeName;
                if (!isset($this->removalMap[$key])) {
                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);
                }

                // Adjust positions to account for additional tokens that must be skipped
                $removalInfo = $this->removalMap[$key];
                if (isset($removalInfo['left'])) {
                    $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1;
                }
                if (isset($removalInfo['right'])) {
                    $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1;
                }
            }

            $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment);

            if (null !== $subNode) {
                $result .= $extraLeft;

                $origIndentLevel = $this->indentLevel;
                $this->setIndentLevel($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment);

                // If it's the same node that was previously in this position, it certainly doesn't
                // need fixup. It's important to check this here, because our fixup checks are more
                // conservative than strictly necessary.
                if (isset($fixupInfo[$subNodeName])
                    && $subNode->getAttribute('origNode') !== $origSubNode
                ) {
                    $fixup = $fixupInfo[$subNodeName];
                    $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos);
                } else {
                    $res = $this->p($subNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
                }

                $this->safeAppend($result, $res);
                $this->setIndentLevel($origIndentLevel);

                $result .= $extraRight;
            }

            $pos = $subEndPos + 1;
        }

        $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment);
        return $result;
    }

    /**
     * Perform a format-preserving pretty print of an array.
     *
     * @param Node[] $nodes New nodes
     * @param Node[] $origNodes Original nodes
     * @param int $pos Current token position (updated by reference)
     * @param int $indentAdjustment Adjustment for indentation
     * @param string $parentNodeClass Class of the containing node.
     * @param string $subNodeName Name of array subnode.
     * @param null|int $fixup Fixup information for array item nodes
     *
     * @return null|string Result of pretty print or null if cannot preserve formatting
     */
    protected function pArray(
        array  $nodes, array $origNodes, int &$pos, int $indentAdjustment,
        string $parentNodeClass, string $subNodeName, ?int $fixup
    ): ?string {
        $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes);

        $mapKey = $parentNodeClass . '->' . $subNodeName;
        $insertStr = $this->listInsertionMap[$mapKey] ?? null;
        $isStmtList = $subNodeName === 'stmts';

        $beforeFirstKeepOrReplace = true;
        $skipRemovedNode = false;
        $delayedAdd = [];
        $lastElemIndentLevel = $this->indentLevel;

        $insertNewline = false;
        if ($insertStr === "\n") {
            $insertStr = '';
            $insertNewline = true;
        }

        if ($isStmtList && \count($origNodes) === 1 && \count($nodes) !== 1) {
            $startPos = $origNodes[0]->getStartTokenPos();
            $endPos = $origNodes[0]->getEndTokenPos();
            \assert($startPos >= 0 && $endPos >= 0);
            if (!$this->origTokens->haveBraces($startPos, $endPos)) {
                // This was a single statement without braces, but either additional statements
                // have been added, or the single statement has been removed. This requires the
                // addition of braces. For now fall back.
                // TODO: Try to preserve formatting
                return null;
            }
        }

        $result = '';
        foreach ($diff as $i => $diffElem) {
            $diffType = $diffElem->type;
            /** @var Node|string|null $arrItem */
            $arrItem = $diffElem->new;
            /** @var Node|string|null $origArrItem */
            $origArrItem = $diffElem->old;

            if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {
                $beforeFirstKeepOrReplace = false;

                if ($origArrItem === null || $arrItem === null) {
                    // We can only handle the case where both are null
                    if ($origArrItem === $arrItem) {
                        continue;
                    }
                    return null;
                }

                if (!$arrItem instanceof Node || !$origArrItem instanceof Node) {
                    // We can only deal with nodes. This can occur for Names, which use string arrays.
                    return null;
                }

                $itemStartPos = $origArrItem->getStartTokenPos();
                $itemEndPos = $origArrItem->getEndTokenPos();
                \assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);

                $origIndentLevel = $this->indentLevel;
                $lastElemIndentLevel = $this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment;
                $this->setIndentLevel($lastElemIndentLevel);

                $comments = $arrItem->getComments();
                $origComments = $origArrItem->getComments();
                $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos;
                \assert($commentStartPos >= 0);

                if ($commentStartPos < $pos) {
                    // Comments may be assigned to multiple nodes if they start at the same position.
                    // Make sure we don't try to print them multiple times.
                    $commentStartPos = $itemStartPos;
                }

                if ($skipRemovedNode) {
                    if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
                        // We'd remove an opening/closing PHP tag.
                        // TODO: Preserve formatting.
                        $this->setIndentLevel($origIndentLevel);
                        return null;
                    }
                } else {
                    $result .= $this->origTokens->getTokenCode(
                        $pos, $commentStartPos, $indentAdjustment);
                }

                if (!empty($delayedAdd)) {
                    /** @var Node $delayedAddNode */
                    foreach ($delayedAdd as $delayedAddNode) {
                        if ($insertNewline) {
                            $delayedAddComments = $delayedAddNode->getComments();
                            if ($delayedAddComments) {
                                $result .= $this->pComments($delayedAddComments) . $this->nl;
                            }
                        }

                        $this->safeAppend($result, $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true));

                        if ($insertNewline) {
                            $result .= $insertStr . $this->nl;
                        } else {
                            $result .= $insertStr;
                        }
                    }

                    $delayedAdd = [];
                }

                if ($comments !== $origComments) {
                    if ($comments) {
                        $result .= $this->pComments($comments) . $this->nl;
                    }
                } else {
                    $result .= $this->origTokens->getTokenCode(
                        $commentStartPos, $itemStartPos, $indentAdjustment);
                }

                // If we had to remove anything, we have done so now.
                $skipRemovedNode = false;
            } elseif ($diffType === DiffElem::TYPE_ADD) {
                if (null === $insertStr) {
                    // We don't have insertion information for this list type
                    return null;
                }

                if (!$arrItem instanceof Node) {
                    // We only support list insertion of nodes.
                    return null;
                }

                // We go multiline if the original code was multiline,
                // or if it's an array item with a comment above it.
                // Match always uses multiline formatting.
                if ($insertStr === ', ' &&
                    ($this->isMultiline($origNodes) || $arrItem->getComments() ||
                     $parentNodeClass === Expr\Match_::class)
                ) {
                    $insertStr = ',';
                    $insertNewline = true;
                }

                if ($beforeFirstKeepOrReplace) {
                    // Will be inserted at the next "replace" or "keep" element
                    $delayedAdd[] = $arrItem;
                    continue;
                }

                $itemStartPos = $pos;
                $itemEndPos = $pos - 1;

                $origIndentLevel = $this->indentLevel;
                $this->setIndentLevel($lastElemIndentLevel);

                if ($insertNewline) {
                    $result .= $insertStr . $this->nl;
                    $comments = $arrItem->getComments();
                    if ($comments) {
                        $result .= $this->pComments($comments) . $this->nl;
                    }
                } else {
                    $result .= $insertStr;
                }
            } elseif ($diffType === DiffElem::TYPE_REMOVE) {
                if (!$origArrItem instanceof Node) {
                    // We only support removal for nodes
                    return null;
                }

                $itemStartPos = $origArrItem->getStartTokenPos();
                $itemEndPos = $origArrItem->getEndTokenPos();
                \assert($itemStartPos >= 0 && $itemEndPos >= 0);

                // Consider comments part of the node.
                $origComments = $origArrItem->getComments();
                if ($origComments) {
                    $itemStartPos = $origComments[0]->getStartTokenPos();
                }

                if ($i === 0) {
                    // If we're removing from the start, keep the tokens before the node and drop those after it,
                    // instead of the other way around.
                    $result .= $this->origTokens->getTokenCode(
                        $pos, $itemStartPos, $indentAdjustment);
                    $skipRemovedNode = true;
                } else {
                    if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {
                        // We'd remove an opening/closing PHP tag.
                        // TODO: Preserve formatting.
                        return null;
                    }
                }

                $pos = $itemEndPos + 1;
                continue;
            } else {
                throw new \Exception("Shouldn't happen");
            }

            if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) {
                $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos);
            } else {
                $res = $this->p($arrItem, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
            }
            $this->safeAppend($result, $res);

            $this->setIndentLevel($origIndentLevel);
            $pos = $itemEndPos + 1;
        }

        if ($skipRemovedNode) {
            // TODO: Support removing single node.
            return null;
        }

        if (!empty($delayedAdd)) {
            if (!isset($this->emptyListInsertionMap[$mapKey])) {
                return null;
            }

            list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey];
            if (null !== $findToken) {
                $insertPos = $this->origTokens->findRight($pos, $findToken) + 1;
                $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment);
                $pos = $insertPos;
            }

            $first = true;
            $result .= $extraLeft;
            foreach ($delayedAdd as $delayedAddNode) {
                if (!$first) {
                    $result .= $insertStr;
                    if ($insertNewline) {
                        $result .= $this->nl;
                    }
                }
                $result .= $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);
                $first = false;
            }
            $result .= $extraRight === "\n" ? $this->nl : $extraRight;
        }

        return $result;
    }

    /**
     * Print node with fixups.
     *
     * Fixups here refer to the addition of extra parentheses, braces or other characters, that
     * are required to preserve program semantics in a certain context (e.g. to maintain precedence
     * or because only certain expressions are allowed in certain places).
     *
     * @param int $fixup Fixup type
     * @param Node $subNode Subnode to print
     * @param string|null $parentClass Class of parent node
     * @param int $subStartPos Original start pos of subnode
     * @param int $subEndPos Original end pos of subnode
     *
     * @return string Result of fixed-up print of subnode
     */
    protected function pFixup(int $fixup, Node $subNode, ?string $parentClass, int $subStartPos, int $subEndPos): string {
        switch ($fixup) {
            case self::FIXUP_PREC_LEFT:
                // We use a conservative approximation where lhsPrecedence == precedence.
                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
                    $precedence = $this->precedenceMap[$parentClass][1];
                    return $this->p($subNode, $precedence, $precedence);
                }
                break;
            case self::FIXUP_PREC_RIGHT:
                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
                    $precedence = $this->precedenceMap[$parentClass][2];
                    return $this->p($subNode, $precedence, $precedence);
                }
                break;
            case self::FIXUP_PREC_UNARY:
                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {
                    $precedence = $this->precedenceMap[$parentClass][0];
                    return $this->p($subNode, $precedence, $precedence);
                }
                break;
            case self::FIXUP_CALL_LHS:
                if ($this->callLhsRequiresParens($subNode)
                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)
                ) {
                    return '(' . $this->p($subNode) . ')';
                }
                break;
            case self::FIXUP_DEREF_LHS:
                if ($this->dereferenceLhsRequiresParens($subNode)
                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)
                ) {
                    return '(' . $this->p($subNode) . ')';
                }
                break;
            case self::FIXUP_STATIC_DEREF_LHS:
                if ($this->staticDereferenceLhsRequiresParens($subNode)
                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)
                ) {
                    return '(' . $this->p($subNode) . ')';
                }
                break;
            case self::FIXUP_NEW:
                if ($this->newOperandRequiresParens($subNode)
                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)) {
                    return '(' . $this->p($subNode) . ')';
                }
                break;
            case self::FIXUP_BRACED_NAME:
            case self::FIXUP_VAR_BRACED_NAME:
                if ($subNode instanceof Expr
                    && !$this->origTokens->haveBraces($subStartPos, $subEndPos)
                ) {
                    return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '')
                        . '{' . $this->p($subNode) . '}';
                }
                break;
            case self::FIXUP_ENCAPSED:
                if (!$subNode instanceof Node\InterpolatedStringPart
                    && !$this->origTokens->haveBraces($subStartPos, $subEndPos)
                ) {
                    return '{' . $this->p($subNode) . '}';
                }
                break;
            default:
                throw new \Exception('Cannot happen');
        }

        // Nothing special to do
        return $this->p($subNode);
    }

    /**
     * Appends to a string, ensuring whitespace between label characters.
     *
     * Example: "echo" and "$x" result in "echo$x", but "echo" and "x" result in "echo x".
     * Without safeAppend the result would be "echox", which does not preserve semantics.
     */
    protected function safeAppend(string &$str, string $append): void {
        if ($str === "") {
            $str = $append;
            return;
        }

        if ($append === "") {
            return;
        }

        if (!$this->labelCharMap[$append[0]]
                || !$this->labelCharMap[$str[\strlen($str) - 1]]) {
            $str .= $append;
        } else {
            $str .= " " . $append;
        }
    }

    /**
     * Determines whether the LHS of a call must be wrapped in parenthesis.
     *
     * @param Node $node LHS of a call
     *
     * @return bool Whether parentheses are required
     */
    protected function callLhsRequiresParens(Node $node): bool {
        return !($node instanceof Node\Name
            || $node instanceof Expr\Variable
            || $node instanceof Expr\ArrayDimFetch
            || $node instanceof Expr\FuncCall
            || $node instanceof Expr\MethodCall
            || $node instanceof Expr\NullsafeMethodCall
            || $node instanceof Expr\StaticCall
            || $node instanceof Expr\Array_);
    }

    /**
     * Determines whether the LHS of an array/object operation must be wrapped in parentheses.
     *
     * @param Node $node LHS of dereferencing operation
     *
     * @return bool Whether parentheses are required
     */
    protected function dereferenceLhsRequiresParens(Node $node): bool {
        // A constant can occur on the LHS of an array/object deref, but not a static deref.
        return $this->staticDereferenceLhsRequiresParens($node)
            && !$node instanceof Expr\ConstFetch;
    }

    /**
     * Determines whether the LHS of a static operation must be wrapped in parentheses.
     *
     * @param Node $node LHS of dereferencing operation
     *
     * @return bool Whether parentheses are required
     */
    protected function staticDereferenceLhsRequiresParens(Node $node): bool {
        return !($node instanceof Expr\Variable
            || $node instanceof Node\Name
            || $node instanceof Expr\ArrayDimFetch
            || $node instanceof Expr\PropertyFetch
            || $node instanceof Expr\NullsafePropertyFetch
            || $node instanceof Expr\StaticPropertyFetch
            || $node instanceof Expr\FuncCall
            || $node instanceof Expr\MethodCall
            || $node instanceof Expr\NullsafeMethodCall
            || $node instanceof Expr\StaticCall
            || $node instanceof Expr\Array_
            || $node instanceof Scalar\String_
            || $node instanceof Expr\ClassConstFetch);
    }

    /**
     * Determines whether an expression used in "new" or "instanceof" requires parentheses.
     *
     * @param Node $node New or instanceof operand
     *
     * @return bool Whether parentheses are required
     */
    protected function newOperandRequiresParens(Node $node): bool {
        if ($node instanceof Node\Name || $node instanceof Expr\Variable) {
            return false;
        }
        if ($node instanceof Expr\ArrayDimFetch || $node instanceof Expr\PropertyFetch ||
            $node instanceof Expr\NullsafePropertyFetch
        ) {
            return $this->newOperandRequiresParens($node->var);
        }
        if ($node instanceof Expr\StaticPropertyFetch) {
            return $this->newOperandRequiresParens($node->class);
        }
        return true;
    }

    /**
     * Print modifiers, including trailing whitespace.
     *
     * @param int $modifiers Modifier mask to print
     *
     * @return string Printed modifiers
     */
    protected function pModifiers(int $modifiers): string {
        return ($modifiers & Modifiers::FINAL ? 'final ' : '')
             . ($modifiers & Modifiers::ABSTRACT ? 'abstract ' : '')
             . ($modifiers & Modifiers::PUBLIC ? 'public ' : '')
             . ($modifiers & Modifiers::PROTECTED ? 'protected ' : '')
             . ($modifiers & Modifiers::PRIVATE ? 'private ' : '')
             . ($modifiers & Modifiers::STATIC ? 'static ' : '')
             . ($modifiers & Modifiers::READONLY ? 'readonly ' : '');
    }

    protected function pStatic(bool $static): string {
        return $static ? 'static ' : '';
    }

    /**
     * Determine whether a list of nodes uses multiline formatting.
     *
     * @param (Node|null)[] $nodes Node list
     *
     * @return bool Whether multiline formatting is used
     */
    protected function isMultiline(array $nodes): bool {
        if (\count($nodes) < 2) {
            return false;
        }

        $pos = -1;
        foreach ($nodes as $node) {
            if (null === $node) {
                continue;
            }

            $endPos = $node->getEndTokenPos() + 1;
            if ($pos >= 0) {
                $text = $this->origTokens->getTokenCode($pos, $endPos, 0);
                if (false === strpos($text, "\n")) {
                    // We require that a newline is present between *every* item. If the formatting
                    // is inconsistent, with only some items having newlines, we don't consider it
                    // as multiline
                    return false;
                }
            }
            $pos = $endPos;
        }

        return true;
    }

    /**
     * Lazily initializes label char map.
     *
     * The label char map determines whether a certain character may occur in a label.
     */
    protected function initializeLabelCharMap(): void {
        if (isset($this->labelCharMap)) {
            return;
        }

        $this->labelCharMap = [];
        for ($i = 0; $i < 256; $i++) {
            $chr = chr($i);
            $this->labelCharMap[$chr] = $i >= 0x80 || ctype_alnum($chr);
        }

        if ($this->phpVersion->allowsDelInIdentifiers()) {
            $this->labelCharMap["\x7f"] = true;
        }
    }

    /**
     * Lazily initializes node list differ.
     *
     * The node list differ is used to determine differences between two array subnodes.
     */
    protected function initializeNodeListDiffer(): void {
        if (isset($this->nodeListDiffer)) {
            return;
        }

        $this->nodeListDiffer = new Internal\Differ(function ($a, $b) {
            if ($a instanceof Node && $b instanceof Node) {
                return $a === $b->getAttribute('origNode');
            }
            // Can happen for array destructuring
            return $a === null && $b === null;
        });
    }

    /**
     * Lazily initializes fixup map.
     *
     * The fixup map is used to determine whether a certain subnode of a certain node may require
     * some kind of "fixup" operation, e.g. the addition of parenthesis or braces.
     */
    protected function initializeFixupMap(): void {
        if (isset($this->fixupMap)) {
            return;
        }

        $this->fixupMap = [
            Expr\Instanceof_::class => [
                'expr' => self::FIXUP_PREC_UNARY,
                'class' => self::FIXUP_NEW,
            ],
            Expr\Ternary::class => [
                'cond' => self::FIXUP_PREC_LEFT,
                'else' => self::FIXUP_PREC_RIGHT,
            ],
            Expr\Yield_::class => ['value' => self::FIXUP_PREC_UNARY],

            Expr\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],
            Expr\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],
            Expr\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],
            Expr\ClassConstFetch::class => [
                'class' => self::FIXUP_STATIC_DEREF_LHS,
                'name' => self::FIXUP_BRACED_NAME,
            ],
            Expr\New_::class => ['class' => self::FIXUP_NEW],
            Expr\MethodCall::class => [
                'var' => self::FIXUP_DEREF_LHS,
                'name' => self::FIXUP_BRACED_NAME,
            ],
            Expr\NullsafeMethodCall::class => [
                'var' => self::FIXUP_DEREF_LHS,
                'name' => self::FIXUP_BRACED_NAME,
            ],
            Expr\StaticPropertyFetch::class => [
                'class' => self::FIXUP_STATIC_DEREF_LHS,
                'name' => self::FIXUP_VAR_BRACED_NAME,
            ],
            Expr\PropertyFetch::class => [
                'var' => self::FIXUP_DEREF_LHS,
                'name' => self::FIXUP_BRACED_NAME,
            ],
            Expr\NullsafePropertyFetch::class => [
                'var' => self::FIXUP_DEREF_LHS,
                'name' => self::FIXUP_BRACED_NAME,
            ],
            Scalar\InterpolatedString::class => [
                'parts' => self::FIXUP_ENCAPSED,
            ],
        ];

        $binaryOps = [
            BinaryOp\Pow::class, BinaryOp\Mul::class, BinaryOp\Div::class, BinaryOp\Mod::class,
            BinaryOp\Plus::class, BinaryOp\Minus::class, BinaryOp\Concat::class,
            BinaryOp\ShiftLeft::class, BinaryOp\ShiftRight::class, BinaryOp\Smaller::class,
            BinaryOp\SmallerOrEqual::class, BinaryOp\Greater::class, BinaryOp\GreaterOrEqual::class,
            BinaryOp\Equal::class, BinaryOp\NotEqual::class, BinaryOp\Identical::class,
            BinaryOp\NotIdentical::class, BinaryOp\Spaceship::class, BinaryOp\BitwiseAnd::class,
            BinaryOp\BitwiseXor::class, BinaryOp\BitwiseOr::class, BinaryOp\BooleanAnd::class,
            BinaryOp\BooleanOr::class, BinaryOp\Coalesce::class, BinaryOp\LogicalAnd::class,
            BinaryOp\LogicalXor::class, BinaryOp\LogicalOr::class,
        ];
        foreach ($binaryOps as $binaryOp) {
            $this->fixupMap[$binaryOp] = [
                'left' => self::FIXUP_PREC_LEFT,
                'right' => self::FIXUP_PREC_RIGHT
            ];
        }

        $prefixOps = [
            Expr\Clone_::class, Expr\BitwiseNot::class, Expr\BooleanNot::class, Expr\UnaryPlus::class, Expr\UnaryMinus::class,
            Cast\Int_::class, Cast\Double::class, Cast\String_::class, Cast\Array_::class,
            Cast\Object_::class, Cast\Bool_::class, Cast\Unset_::class, Expr\ErrorSuppress::class,
            Expr\YieldFrom::class, Expr\Print_::class, Expr\Include_::class,
            Expr\Assign::class, Expr\AssignRef::class, AssignOp\Plus::class, AssignOp\Minus::class,
            AssignOp\Mul::class, AssignOp\Div::class, AssignOp\Concat::class, AssignOp\Mod::class,
            AssignOp\BitwiseAnd::class, AssignOp\BitwiseOr::class, AssignOp\BitwiseXor::class,
            AssignOp\ShiftLeft::class, AssignOp\ShiftRight::class, AssignOp\Pow::class, AssignOp\Coalesce::class,
            Expr\ArrowFunction::class, Expr\Throw_::class,
        ];
        foreach ($prefixOps as $prefixOp) {
            $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_UNARY];
        }
    }

    /**
     * Lazily initializes the removal map.
     *
     * The removal map is used to determine which additional tokens should be removed when a
     * certain node is replaced by null.
     */
    protected function initializeRemovalMap(): void {
        if (isset($this->removalMap)) {
            return;
        }

        $stripBoth = ['left' => \T_WHITESPACE, 'right' => \T_WHITESPACE];
        $stripLeft = ['left' => \T_WHITESPACE];
        $stripRight = ['right' => \T_WHITESPACE];
        $stripDoubleArrow = ['right' => \T_DOUBLE_ARROW];
        $stripColon = ['left' => ':'];
        $stripEquals = ['left' => '='];
        $this->removalMap = [
            'Expr_ArrayDimFetch->dim' => $stripBoth,
            'ArrayItem->key' => $stripDoubleArrow,
            'Expr_ArrowFunction->returnType' => $stripColon,
            'Expr_Closure->returnType' => $stripColon,
            'Expr_Exit->expr' => $stripBoth,
            'Expr_Ternary->if' => $stripBoth,
            'Expr_Yield->key' => $stripDoubleArrow,
            'Expr_Yield->value' => $stripBoth,
            'Param->type' => $stripRight,
            'Param->default' => $stripEquals,
            'Stmt_Break->num' => $stripBoth,
            'Stmt_Catch->var' => $stripLeft,
            'Stmt_ClassConst->type' => $stripRight,
            'Stmt_ClassMethod->returnType' => $stripColon,
            'Stmt_Class->extends' => ['left' => \T_EXTENDS],
            'Stmt_Enum->scalarType' => $stripColon,
            'Stmt_EnumCase->expr' => $stripEquals,
            'Expr_PrintableNewAnonClass->extends' => ['left' => \T_EXTENDS],
            'Stmt_Continue->num' => $stripBoth,
            'Stmt_Foreach->keyVar' => $stripDoubleArrow,
            'Stmt_Function->returnType' => $stripColon,
            'Stmt_If->else' => $stripLeft,
            'Stmt_Namespace->name' => $stripLeft,
            'Stmt_Property->type' => $stripRight,
            'PropertyItem->default' => $stripEquals,
            'Stmt_Return->expr' => $stripBoth,
            'Stmt_StaticVar->default' => $stripEquals,
            'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft,
            'Stmt_TryCatch->finally' => $stripLeft,
            // 'Stmt_Case->cond': Replace with "default"
            // 'Stmt_Class->name': Unclear what to do
            // 'Stmt_Declare->stmts': Not a plain node
            // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a plain node
        ];
    }

    protected function initializeInsertionMap(): void {
        if (isset($this->insertionMap)) {
            return;
        }

        // TODO: "yield" where both key and value are inserted doesn't work
        // [$find, $beforeToken, $extraLeft, $extraRight]
        $this->insertionMap = [
            'Expr_ArrayDimFetch->dim' => ['[', false, null, null],
            'ArrayItem->key' => [null, false, null, ' => '],
            'Expr_ArrowFunction->returnType' => [')', false, ': ', null],
            'Expr_Closure->returnType' => [')', false, ': ', null],
            'Expr_Ternary->if' => ['?', false, ' ', ' '],
            'Expr_Yield->key' => [\T_YIELD, false, null, ' => '],
            'Expr_Yield->value' => [\T_YIELD, false, ' ', null],
            'Param->type' => [null, false, null, ' '],
            'Param->default' => [null, false, ' = ', null],
            'Stmt_Break->num' => [\T_BREAK, false, ' ', null],
            'Stmt_Catch->var' => [null, false, ' ', null],
            'Stmt_ClassMethod->returnType' => [')', false, ': ', null],
            'Stmt_ClassConst->type' => [\T_CONST, false, ' ', null],
            'Stmt_Class->extends' => [null, false, ' extends ', null],
            'Stmt_Enum->scalarType' => [null, false, ' : ', null],
            'Stmt_EnumCase->expr' => [null, false, ' = ', null],
            'Expr_PrintableNewAnonClass->extends' => [null, false, ' extends ', null],
            'Stmt_Continue->num' => [\T_CONTINUE, false, ' ', null],
            'Stmt_Foreach->keyVar' => [\T_AS, false, null, ' => '],
            'Stmt_Function->returnType' => [')', false, ': ', null],
            'Stmt_If->else' => [null, false, ' ', null],
            'Stmt_Namespace->name' => [\T_NAMESPACE, false, ' ', null],
            'Stmt_Property->type' => [\T_VARIABLE, true, null, ' '],
            'PropertyItem->default' => [null, false, ' = ', null],
            'Stmt_Return->expr' => [\T_RETURN, false, ' ', null],
            'Stmt_StaticVar->default' => [null, false, ' = ', null],
            //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO
            'Stmt_TryCatch->finally' => [null, false, ' ', null],

            // 'Expr_Exit->expr': Complicated due to optional ()
            // 'Stmt_Case->cond': Conversion from default to case
            // 'Stmt_Class->name': Unclear
            // 'Stmt_Declare->stmts': Not a proper node
            // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a proper node
        ];
    }

    protected function initializeListInsertionMap(): void {
        if (isset($this->listInsertionMap)) {
            return;
        }

        $this->listInsertionMap = [
            // special
            //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully
            //'Scalar_InterpolatedString->parts' => '',
            Stmt\Catch_::class . '->types' => '|',
            UnionType::class . '->types' => '|',
            IntersectionType::class . '->types' => '&',
            Stmt\If_::class . '->elseifs' => ' ',
            Stmt\TryCatch::class . '->catches' => ' ',

            // comma-separated lists
            Expr\Array_::class . '->items' => ', ',
            Expr\ArrowFunction::class . '->params' => ', ',
            Expr\Closure::class . '->params' => ', ',
            Expr\Closure::class . '->uses' => ', ',
            Expr\FuncCall::class . '->args' => ', ',
            Expr\Isset_::class . '->vars' => ', ',
            Expr\List_::class . '->items' => ', ',
            Expr\MethodCall::class . '->args' => ', ',
            Expr\NullsafeMethodCall::class . '->args' => ', ',
            Expr\New_::class . '->args' => ', ',
            PrintableNewAnonClassNode::class . '->args' => ', ',
            Expr\StaticCall::class . '->args' => ', ',
            Stmt\ClassConst::class . '->consts' => ', ',
            Stmt\ClassMethod::class . '->params' => ', ',
            Stmt\Class_::class . '->implements' => ', ',
            Stmt\Enum_::class . '->implements' => ', ',
            PrintableNewAnonClassNode::class . '->implements' => ', ',
            Stmt\Const_::class . '->consts' => ', ',
            Stmt\Declare_::class . '->declares' => ', ',
            Stmt\Echo_::class . '->exprs' => ', ',
            Stmt\For_::class . '->init' => ', ',
            Stmt\For_::class . '->cond' => ', ',
            Stmt\For_::class . '->loop' => ', ',
            Stmt\Function_::class . '->params' => ', ',
            Stmt\Global_::class . '->vars' => ', ',
            Stmt\GroupUse::class . '->uses' => ', ',
            Stmt\Interface_::class . '->extends' => ', ',
            Expr\Match_::class . '->arms' => ', ',
            Stmt\Property::class . '->props' => ', ',
            Stmt\StaticVar::class . '->vars' => ', ',
            Stmt\TraitUse::class . '->traits' => ', ',
            Stmt\TraitUseAdaptation\Precedence::class . '->insteadof' => ', ',
            Stmt\Unset_::class .  '->vars' => ', ',
            Stmt\UseUse::class . '->uses' => ', ',
            MatchArm::class . '->conds' => ', ',
            AttributeGroup::class . '->attrs' => ', ',

            // statement lists
            Expr\Closure::class . '->stmts' => "\n",
            Stmt\Case_::class . '->stmts' => "\n",
            Stmt\Catch_::class . '->stmts' => "\n",
            Stmt\Class_::class . '->stmts' => "\n",
            Stmt\Enum_::class . '->stmts' => "\n",
            PrintableNewAnonClassNode::class . '->stmts' => "\n",
            Stmt\Interface_::class . '->stmts' => "\n",
            Stmt\Trait_::class . '->stmts' => "\n",
            Stmt\ClassMethod::class . '->stmts' => "\n",
            Stmt\Declare_::class . '->stmts' => "\n",
            Stmt\Do_::class . '->stmts' => "\n",
            Stmt\ElseIf_::class . '->stmts' => "\n",
            Stmt\Else_::class . '->stmts' => "\n",
            Stmt\Finally_::class . '->stmts' => "\n",
            Stmt\Foreach_::class . '->stmts' => "\n",
            Stmt\For_::class . '->stmts' => "\n",
            Stmt\Function_::class . '->stmts' => "\n",
            Stmt\If_::class . '->stmts' => "\n",
            Stmt\Namespace_::class . '->stmts' => "\n",
            Stmt\Block::class . '->stmts' => "\n",

            // Attribute groups
            Stmt\Class_::class . '->attrGroups' => "\n",
            Stmt\Enum_::class . '->attrGroups' => "\n",
            Stmt\EnumCase::class . '->attrGroups' => "\n",
            Stmt\Interface_::class . '->attrGroups' => "\n",
            Stmt\Trait_::class . '->attrGroups' => "\n",
            Stmt\Function_::class . '->attrGroups' => "\n",
            Stmt\ClassMethod::class . '->attrGroups' => "\n",
            Stmt\ClassConst::class . '->attrGroups' => "\n",
            Stmt\Property::class . '->attrGroups' => "\n",
            PrintableNewAnonClassNode::class . '->attrGroups' => ' ',
            Expr\Closure::class . '->attrGroups' => ' ',
            Expr\ArrowFunction::class . '->attrGroups' => ' ',
            Param::class . '->attrGroups' => ' ',
            Stmt\Switch_::class . '->cases' => "\n",
            Stmt\TraitUse::class . '->adaptations' => "\n",
            Stmt\TryCatch::class . '->stmts' => "\n",
            Stmt\While_::class . '->stmts' => "\n",

            // dummy for top-level context
            'File->stmts' => "\n",
        ];
    }

    protected function initializeEmptyListInsertionMap(): void {
        if (isset($this->emptyListInsertionMap)) {
            return;
        }

        // TODO Insertion into empty statement lists.

        // [$find, $extraLeft, $extraRight]
        $this->emptyListInsertionMap = [
            Expr\ArrowFunction::class . '->params' => ['(', '', ''],
            Expr\Closure::class . '->uses' => [')', ' use (', ')'],
            Expr\Closure::class . '->params' => ['(', '', ''],
            Expr\FuncCall::class . '->args' => ['(', '', ''],
            Expr\MethodCall::class . '->args' => ['(', '', ''],
            Expr\NullsafeMethodCall::class . '->args' => ['(', '', ''],
            Expr\New_::class . '->args' => ['(', '', ''],
            PrintableNewAnonClassNode::class . '->args' => ['(', '', ''],
            PrintableNewAnonClassNode::class . '->implements' => [null, ' implements ', ''],
            Expr\StaticCall::class . '->args' => ['(', '', ''],
            Stmt\Class_::class . '->implements' => [null, ' implements ', ''],
            Stmt\Enum_::class . '->implements' => [null, ' implements ', ''],
            Stmt\ClassMethod::class . '->params' => ['(', '', ''],
            Stmt\Interface_::class . '->extends' => [null, ' extends ', ''],
            Stmt\Function_::class . '->params' => ['(', '', ''],
            Stmt\Interface_::class . '->attrGroups' => [null, '', "\n"],
            Stmt\Class_::class . '->attrGroups' => [null, '', "\n"],
            Stmt\ClassConst::class . '->attrGroups' => [null, '', "\n"],
            Stmt\ClassMethod::class . '->attrGroups' => [null, '', "\n"],
            Stmt\Function_::class . '->attrGroups' => [null, '', "\n"],
            Stmt\Property::class . '->attrGroups' => [null, '', "\n"],
            Stmt\Trait_::class . '->attrGroups' => [null, '', "\n"],
            Expr\ArrowFunction::class . '->attrGroups' => [null, '', ' '],
            Expr\Closure::class . '->attrGroups' => [null, '', ' '],
            PrintableNewAnonClassNode::class . '->attrGroups' => [\T_NEW, ' ', ''],

            /* These cannot be empty to start with:
             * Expr_Isset->vars
             * Stmt_Catch->types
             * Stmt_Const->consts
             * Stmt_ClassConst->consts
             * Stmt_Declare->declares
             * Stmt_Echo->exprs
             * Stmt_Global->vars
             * Stmt_GroupUse->uses
             * Stmt_Property->props
             * Stmt_StaticVar->vars
             * Stmt_TraitUse->traits
             * Stmt_TraitUseAdaptation_Precedence->insteadof
             * Stmt_Unset->vars
             * Stmt_Use->uses
             * UnionType->types
             */

            /* TODO
             * Stmt_If->elseifs
             * Stmt_TryCatch->catches
             * Expr_Array->items
             * Expr_List->items
             * Stmt_For->init
             * Stmt_For->cond
             * Stmt_For->loop
             */
        ];
    }

    protected function initializeModifierChangeMap(): void {
        if (isset($this->modifierChangeMap)) {
            return;
        }

        $this->modifierChangeMap = [
            Stmt\ClassConst::class . '->flags' => ['pModifiers', \T_CONST],
            Stmt\ClassMethod::class . '->flags' => ['pModifiers', \T_FUNCTION],
            Stmt\Class_::class . '->flags' => ['pModifiers', \T_CLASS],
            Stmt\Property::class . '->flags' => ['pModifiers', \T_VARIABLE],
            PrintableNewAnonClassNode::class . '->flags' => ['pModifiers', \T_CLASS],
            Param::class . '->flags' => ['pModifiers', \T_VARIABLE],
            Expr\Closure::class . '->static' => ['pStatic', \T_FUNCTION],
            Expr\ArrowFunction::class . '->static' => ['pStatic', \T_FN],
            //Stmt\TraitUseAdaptation\Alias::class . '->newModifier' => 0, // TODO
        ];

        // List of integer subnodes that are not modifiers:
        // Expr_Include->type
        // Stmt_GroupUse->type
        // Stmt_Use->type
        // UseItem->type
    }
}
Comment/Doc.php000064400000000147151520657540007400 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Comment;

class Doc extends \PhpParser\Comment {
}
PrettyPrinter/Standard.php000064400000145544151520657540011677 0ustar00<?php declare(strict_types=1);

namespace PhpParser\PrettyPrinter;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\AssignOp;
use PhpParser\Node\Expr\BinaryOp;
use PhpParser\Node\Expr\Cast;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Scalar\MagicConst;
use PhpParser\Node\Stmt;
use PhpParser\PrettyPrinterAbstract;

class Standard extends PrettyPrinterAbstract {
    // Special nodes

    protected function pParam(Node\Param $node): string {
        return $this->pAttrGroups($node->attrGroups, true)
             . $this->pModifiers($node->flags)
             . ($node->type ? $this->p($node->type) . ' ' : '')
             . ($node->byRef ? '&' : '')
             . ($node->variadic ? '...' : '')
             . $this->p($node->var)
             . ($node->default ? ' = ' . $this->p($node->default) : '');
    }

    protected function pArg(Node\Arg $node): string {
        return ($node->name ? $node->name->toString() . ': ' : '')
             . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '')
             . $this->p($node->value);
    }

    protected function pVariadicPlaceholder(Node\VariadicPlaceholder $node): string {
        return '...';
    }

    protected function pConst(Node\Const_ $node): string {
        return $node->name . ' = ' . $this->p($node->value);
    }

    protected function pNullableType(Node\NullableType $node): string {
        return '?' . $this->p($node->type);
    }

    protected function pUnionType(Node\UnionType $node): string {
        $types = [];
        foreach ($node->types as $typeNode) {
            if ($typeNode instanceof Node\IntersectionType) {
                $types[] = '('. $this->p($typeNode) . ')';
                continue;
            }
            $types[] = $this->p($typeNode);
        }
        return implode('|', $types);
    }

    protected function pIntersectionType(Node\IntersectionType $node): string {
        return $this->pImplode($node->types, '&');
    }

    protected function pIdentifier(Node\Identifier $node): string {
        return $node->name;
    }

    protected function pVarLikeIdentifier(Node\VarLikeIdentifier $node): string {
        return '$' . $node->name;
    }

    protected function pAttribute(Node\Attribute $node): string {
        return $this->p($node->name)
             . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : '');
    }

    protected function pAttributeGroup(Node\AttributeGroup $node): string {
        return '#[' . $this->pCommaSeparated($node->attrs) . ']';
    }

    // Names

    protected function pName(Name $node): string {
        return $node->name;
    }

    protected function pName_FullyQualified(Name\FullyQualified $node): string {
        return '\\' . $node->name;
    }

    protected function pName_Relative(Name\Relative $node): string {
        return 'namespace\\' . $node->name;
    }

    // Magic Constants

    protected function pScalar_MagicConst_Class(MagicConst\Class_ $node): string {
        return '__CLASS__';
    }

    protected function pScalar_MagicConst_Dir(MagicConst\Dir $node): string {
        return '__DIR__';
    }

    protected function pScalar_MagicConst_File(MagicConst\File $node): string {
        return '__FILE__';
    }

    protected function pScalar_MagicConst_Function(MagicConst\Function_ $node): string {
        return '__FUNCTION__';
    }

    protected function pScalar_MagicConst_Line(MagicConst\Line $node): string {
        return '__LINE__';
    }

    protected function pScalar_MagicConst_Method(MagicConst\Method $node): string {
        return '__METHOD__';
    }

    protected function pScalar_MagicConst_Namespace(MagicConst\Namespace_ $node): string {
        return '__NAMESPACE__';
    }

    protected function pScalar_MagicConst_Trait(MagicConst\Trait_ $node): string {
        return '__TRAIT__';
    }

    // Scalars

    private function indentString(string $str): string {
        return str_replace("\n", $this->nl, $str);
    }

    protected function pScalar_String(Scalar\String_ $node): string {
        $kind = $node->getAttribute('kind', Scalar\String_::KIND_SINGLE_QUOTED);
        switch ($kind) {
            case Scalar\String_::KIND_NOWDOC:
                $label = $node->getAttribute('docLabel');
                if ($label && !$this->containsEndLabel($node->value, $label)) {
                    $shouldIdent = $this->phpVersion->supportsFlexibleHeredoc();
                    $nl = $shouldIdent ? $this->nl : $this->newline;
                    if ($node->value === '') {
                        return "<<<'$label'$nl$label{$this->docStringEndToken}";
                    }

                    // Make sure trailing \r is not combined with following \n into CRLF.
                    if ($node->value[strlen($node->value) - 1] !== "\r") {
                        $value = $shouldIdent ? $this->indentString($node->value) : $node->value;
                        return "<<<'$label'$nl$value$nl$label{$this->docStringEndToken}";
                    }
                }
                /* break missing intentionally */
                // no break
            case Scalar\String_::KIND_SINGLE_QUOTED:
                return $this->pSingleQuotedString($node->value);
            case Scalar\String_::KIND_HEREDOC:
                $label = $node->getAttribute('docLabel');
                $escaped = $this->escapeString($node->value, null);
                if ($label && !$this->containsEndLabel($escaped, $label)) {
                    $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline;
                    if ($escaped === '') {
                        return "<<<$label$nl$label{$this->docStringEndToken}";
                    }

                    return "<<<$label$nl$escaped$nl$label{$this->docStringEndToken}";
                }
                /* break missing intentionally */
                // no break
            case Scalar\String_::KIND_DOUBLE_QUOTED:
                return '"' . $this->escapeString($node->value, '"') . '"';
        }
        throw new \Exception('Invalid string kind');
    }

    protected function pScalar_InterpolatedString(Scalar\InterpolatedString $node): string {
        if ($node->getAttribute('kind') === Scalar\String_::KIND_HEREDOC) {
            $label = $node->getAttribute('docLabel');
            if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) {
                $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline;
                if (count($node->parts) === 1
                    && $node->parts[0] instanceof Node\InterpolatedStringPart
                    && $node->parts[0]->value === ''
                ) {
                    return "<<<$label$nl$label{$this->docStringEndToken}";
                }

                return "<<<$label$nl" . $this->pEncapsList($node->parts, null)
                     . "$nl$label{$this->docStringEndToken}";
            }
        }
        return '"' . $this->pEncapsList($node->parts, '"') . '"';
    }

    protected function pScalar_Int(Scalar\Int_ $node): string {
        if ($node->value === -\PHP_INT_MAX - 1) {
            // PHP_INT_MIN cannot be represented as a literal,
            // because the sign is not part of the literal
            return '(-' . \PHP_INT_MAX . '-1)';
        }

        $kind = $node->getAttribute('kind', Scalar\Int_::KIND_DEC);
        if (Scalar\Int_::KIND_DEC === $kind) {
            return (string) $node->value;
        }

        if ($node->value < 0) {
            $sign = '-';
            $str = (string) -$node->value;
        } else {
            $sign = '';
            $str = (string) $node->value;
        }
        switch ($kind) {
            case Scalar\Int_::KIND_BIN:
                return $sign . '0b' . base_convert($str, 10, 2);
            case Scalar\Int_::KIND_OCT:
                return $sign . '0' . base_convert($str, 10, 8);
            case Scalar\Int_::KIND_HEX:
                return $sign . '0x' . base_convert($str, 10, 16);
        }
        throw new \Exception('Invalid number kind');
    }

    protected function pScalar_Float(Scalar\Float_ $node): string {
        if (!is_finite($node->value)) {
            if ($node->value === \INF) {
                return '1.0E+1000';
            }
            if ($node->value === -\INF) {
                return '-1.0E+1000';
            } else {
                return '\NAN';
            }
        }

        // Try to find a short full-precision representation
        $stringValue = sprintf('%.16G', $node->value);
        if ($node->value !== (float) $stringValue) {
            $stringValue = sprintf('%.17G', $node->value);
        }

        // %G is locale dependent and there exists no locale-independent alternative. We don't want
        // mess with switching locales here, so let's assume that a comma is the only non-standard
        // decimal separator we may encounter...
        $stringValue = str_replace(',', '.', $stringValue);

        // ensure that number is really printed as float
        return preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue;
    }

    // Assignments

    protected function pExpr_Assign(Expr\Assign $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\Assign::class, $this->p($node->var) . ' = ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignRef(Expr\AssignRef $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\AssignRef::class, $this->p($node->var) . ' =& ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Plus(AssignOp\Plus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Plus::class, $this->p($node->var) . ' += ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Minus(AssignOp\Minus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Minus::class, $this->p($node->var) . ' -= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Mul(AssignOp\Mul $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Mul::class, $this->p($node->var) . ' *= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Div(AssignOp\Div $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Div::class, $this->p($node->var) . ' /= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Concat(AssignOp\Concat $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Concat::class, $this->p($node->var) . ' .= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Mod(AssignOp\Mod $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Mod::class, $this->p($node->var) . ' %= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_BitwiseAnd(AssignOp\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\BitwiseAnd::class, $this->p($node->var) . ' &= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_BitwiseOr(AssignOp\BitwiseOr $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\BitwiseOr::class, $this->p($node->var) . ' |= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_BitwiseXor(AssignOp\BitwiseXor $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\BitwiseXor::class, $this->p($node->var) . ' ^= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_ShiftLeft(AssignOp\ShiftLeft $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\ShiftLeft::class, $this->p($node->var) . ' <<= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_ShiftRight(AssignOp\ShiftRight $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\ShiftRight::class, $this->p($node->var) . ' >>= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Pow(AssignOp\Pow $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Pow::class, $this->p($node->var) . ' **= ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_AssignOp_Coalesce(AssignOp\Coalesce $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(AssignOp\Coalesce::class, $this->p($node->var) . ' ??= ', $node->expr, $precedence, $lhsPrecedence);
    }

    // Binary expressions

    protected function pExpr_BinaryOp_Plus(BinaryOp\Plus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Plus::class, $node->left, ' + ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Minus(BinaryOp\Minus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Minus::class, $node->left, ' - ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Mul(BinaryOp\Mul $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Mul::class, $node->left, ' * ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Div(BinaryOp\Div $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Div::class, $node->left, ' / ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Concat(BinaryOp\Concat $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Concat::class, $node->left, ' . ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Mod(BinaryOp\Mod $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Mod::class, $node->left, ' % ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\BooleanAnd $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\BooleanAnd::class, $node->left, ' && ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_BooleanOr(BinaryOp\BooleanOr $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\BooleanOr::class, $node->left, ' || ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\BitwiseAnd::class, $node->left, ' & ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\BitwiseOr $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\BitwiseOr::class, $node->left, ' | ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\BitwiseXor $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\BitwiseXor::class, $node->left, ' ^ ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\ShiftLeft $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\ShiftLeft::class, $node->left, ' << ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_ShiftRight(BinaryOp\ShiftRight $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\ShiftRight::class, $node->left, ' >> ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Pow(BinaryOp\Pow $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Pow::class, $node->left, ' ** ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\LogicalAnd $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\LogicalAnd::class, $node->left, ' and ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_LogicalOr(BinaryOp\LogicalOr $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\LogicalOr::class, $node->left, ' or ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_LogicalXor(BinaryOp\LogicalXor $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\LogicalXor::class, $node->left, ' xor ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Equal(BinaryOp\Equal $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Equal::class, $node->left, ' == ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_NotEqual(BinaryOp\NotEqual $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\NotEqual::class, $node->left, ' != ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Identical(BinaryOp\Identical $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Identical::class, $node->left, ' === ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_NotIdentical(BinaryOp\NotIdentical $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\NotIdentical::class, $node->left, ' !== ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Spaceship(BinaryOp\Spaceship $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Spaceship::class, $node->left, ' <=> ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Greater(BinaryOp\Greater $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Greater::class, $node->left, ' > ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\GreaterOrEqual $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\GreaterOrEqual::class, $node->left, ' >= ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Smaller(BinaryOp\Smaller $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Smaller::class, $node->left, ' < ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\SmallerOrEqual $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\SmallerOrEqual::class, $node->left, ' <= ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BinaryOp_Coalesce(BinaryOp\Coalesce $node, int $precedence, int $lhsPrecedence): string {
        return $this->pInfixOp(BinaryOp\Coalesce::class, $node->left, ' ?? ', $node->right, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Instanceof(Expr\Instanceof_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPostfixOp(
            Expr\Instanceof_::class, $node->expr,
            ' instanceof ' . $this->pNewOperand($node->class),
            $precedence, $lhsPrecedence);
    }

    // Unary expressions

    protected function pExpr_BooleanNot(Expr\BooleanNot $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\BooleanNot::class, '!', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_BitwiseNot(Expr\BitwiseNot $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\BitwiseNot::class, '~', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_UnaryMinus(Expr\UnaryMinus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\UnaryMinus::class, '-', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_UnaryPlus(Expr\UnaryPlus $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\UnaryPlus::class, '+', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_PreInc(Expr\PreInc $node): string {
        return '++' . $this->p($node->var);
    }

    protected function pExpr_PreDec(Expr\PreDec $node): string {
        return '--' . $this->p($node->var);
    }

    protected function pExpr_PostInc(Expr\PostInc $node): string {
        return $this->p($node->var) . '++';
    }

    protected function pExpr_PostDec(Expr\PostDec $node): string {
        return $this->p($node->var) . '--';
    }

    protected function pExpr_ErrorSuppress(Expr\ErrorSuppress $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\ErrorSuppress::class, '@', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_YieldFrom(Expr\YieldFrom $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\YieldFrom::class, 'yield from ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Print(Expr\Print_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\Print_::class, 'print ', $node->expr, $precedence, $lhsPrecedence);
    }

    // Casts

    protected function pExpr_Cast_Int(Cast\Int_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\Int_::class, '(int) ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_Double(Cast\Double $node, int $precedence, int $lhsPrecedence): string {
        $kind = $node->getAttribute('kind', Cast\Double::KIND_DOUBLE);
        if ($kind === Cast\Double::KIND_DOUBLE) {
            $cast = '(double)';
        } elseif ($kind === Cast\Double::KIND_FLOAT) {
            $cast = '(float)';
        } else {
            assert($kind === Cast\Double::KIND_REAL);
            $cast = '(real)';
        }
        return $this->pPrefixOp(Cast\Double::class, $cast . ' ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_String(Cast\String_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\String_::class, '(string) ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_Array(Cast\Array_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\Array_::class, '(array) ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_Object(Cast\Object_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\Object_::class, '(object) ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_Bool(Cast\Bool_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\Bool_::class, '(bool) ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Cast_Unset(Cast\Unset_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Cast\Unset_::class, '(unset) ', $node->expr, $precedence, $lhsPrecedence);
    }

    // Function calls and similar constructs

    protected function pExpr_FuncCall(Expr\FuncCall $node): string {
        return $this->pCallLhs($node->name)
             . '(' . $this->pMaybeMultiline($node->args) . ')';
    }

    protected function pExpr_MethodCall(Expr\MethodCall $node): string {
        return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name)
             . '(' . $this->pMaybeMultiline($node->args) . ')';
    }

    protected function pExpr_NullsafeMethodCall(Expr\NullsafeMethodCall $node): string {
        return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name)
            . '(' . $this->pMaybeMultiline($node->args) . ')';
    }

    protected function pExpr_StaticCall(Expr\StaticCall $node): string {
        return $this->pStaticDereferenceLhs($node->class) . '::'
             . ($node->name instanceof Expr
                ? ($node->name instanceof Expr\Variable
                   ? $this->p($node->name)
                   : '{' . $this->p($node->name) . '}')
                : $node->name)
             . '(' . $this->pMaybeMultiline($node->args) . ')';
    }

    protected function pExpr_Empty(Expr\Empty_ $node): string {
        return 'empty(' . $this->p($node->expr) . ')';
    }

    protected function pExpr_Isset(Expr\Isset_ $node): string {
        return 'isset(' . $this->pCommaSeparated($node->vars) . ')';
    }

    protected function pExpr_Eval(Expr\Eval_ $node): string {
        return 'eval(' . $this->p($node->expr) . ')';
    }

    protected function pExpr_Include(Expr\Include_ $node, int $precedence, int $lhsPrecedence): string {
        static $map = [
            Expr\Include_::TYPE_INCLUDE      => 'include',
            Expr\Include_::TYPE_INCLUDE_ONCE => 'include_once',
            Expr\Include_::TYPE_REQUIRE      => 'require',
            Expr\Include_::TYPE_REQUIRE_ONCE => 'require_once',
        ];

        return $this->pPrefixOp(Expr\Include_::class, $map[$node->type] . ' ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_List(Expr\List_ $node): string {
        $syntax = $node->getAttribute('kind',
            $this->phpVersion->supportsShortArrayDestructuring() ? Expr\List_::KIND_ARRAY : Expr\List_::KIND_LIST);
        if ($syntax === Expr\List_::KIND_ARRAY) {
            return '[' . $this->pMaybeMultiline($node->items, true) . ']';
        } else {
            return 'list(' . $this->pMaybeMultiline($node->items, true) . ')';
        }
    }

    // Other

    protected function pExpr_Error(Expr\Error $node): string {
        throw new \LogicException('Cannot pretty-print AST with Error nodes');
    }

    protected function pExpr_Variable(Expr\Variable $node): string {
        if ($node->name instanceof Expr) {
            return '${' . $this->p($node->name) . '}';
        } else {
            return '$' . $node->name;
        }
    }

    protected function pExpr_Array(Expr\Array_ $node): string {
        $syntax = $node->getAttribute('kind',
            $this->shortArraySyntax ? Expr\Array_::KIND_SHORT : Expr\Array_::KIND_LONG);
        if ($syntax === Expr\Array_::KIND_SHORT) {
            return '[' . $this->pMaybeMultiline($node->items, true) . ']';
        } else {
            return 'array(' . $this->pMaybeMultiline($node->items, true) . ')';
        }
    }

    protected function pKey(?Node $node): string {
        if ($node === null) {
            return '';
        }

        // => is not really an operator and does not typically participate in precedence resolution.
        // However, there is an exception if yield expressions with keys are involved:
        // [yield $a => $b] is interpreted as [(yield $a => $b)], so we need to ensure that
        // [(yield $a) => $b] is printed with parentheses. We approximate this by lowering the LHS
        // precedence to that of yield (which will also print unnecessary parentheses for rare low
        // precedence unary operators like include).
        $yieldPrecedence = $this->precedenceMap[Expr\Yield_::class][0];
        return $this->p($node, self::MAX_PRECEDENCE, $yieldPrecedence) . ' => ';
    }

    protected function pArrayItem(Node\ArrayItem $node): string {
        return $this->pKey($node->key)
             . ($node->byRef ? '&' : '')
             . ($node->unpack ? '...' : '')
             . $this->p($node->value);
    }

    protected function pExpr_ArrayDimFetch(Expr\ArrayDimFetch $node): string {
        return $this->pDereferenceLhs($node->var)
             . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';
    }

    protected function pExpr_ConstFetch(Expr\ConstFetch $node): string {
        return $this->p($node->name);
    }

    protected function pExpr_ClassConstFetch(Expr\ClassConstFetch $node): string {
        return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);
    }

    protected function pExpr_PropertyFetch(Expr\PropertyFetch $node): string {
        return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name);
    }

    protected function pExpr_NullsafePropertyFetch(Expr\NullsafePropertyFetch $node): string {
        return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name);
    }

    protected function pExpr_StaticPropertyFetch(Expr\StaticPropertyFetch $node): string {
        return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);
    }

    protected function pExpr_ShellExec(Expr\ShellExec $node): string {
        return '`' . $this->pEncapsList($node->parts, '`') . '`';
    }

    protected function pExpr_Closure(Expr\Closure $node): string {
        return $this->pAttrGroups($node->attrGroups, true)
             . $this->pStatic($node->static)
             . 'function ' . ($node->byRef ? '&' : '')
             . '(' . $this->pMaybeMultiline($node->params, $this->phpVersion->supportsTrailingCommaInParamList()) . ')'
             . (!empty($node->uses) ? ' use (' . $this->pCommaSeparated($node->uses) . ')' : '')
             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')
             . ' {' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pExpr_Match(Expr\Match_ $node): string {
        return 'match (' . $this->p($node->cond) . ') {'
            . $this->pCommaSeparatedMultiline($node->arms, true)
            . $this->nl
            . '}';
    }

    protected function pMatchArm(Node\MatchArm $node): string {
        $result = '';
        if ($node->conds) {
            for ($i = 0, $c = \count($node->conds); $i + 1 < $c; $i++) {
                $result .= $this->p($node->conds[$i]) . ', ';
            }
            $result .= $this->pKey($node->conds[$i]);
        } else {
            $result = 'default => ';
        }
        return $result . $this->p($node->body);
    }

    protected function pExpr_ArrowFunction(Expr\ArrowFunction $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(
            Expr\ArrowFunction::class,
            $this->pAttrGroups($node->attrGroups, true)
            . $this->pStatic($node->static)
            . 'fn' . ($node->byRef ? '&' : '')
            . '(' . $this->pMaybeMultiline($node->params, $this->phpVersion->supportsTrailingCommaInParamList()) . ')'
            . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')
            . ' => ',
            $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pClosureUse(Node\ClosureUse $node): string {
        return ($node->byRef ? '&' : '') . $this->p($node->var);
    }

    protected function pExpr_New(Expr\New_ $node): string {
        if ($node->class instanceof Stmt\Class_) {
            $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : '';
            return 'new ' . $this->pClassCommon($node->class, $args);
        }
        return 'new ' . $this->pNewOperand($node->class)
            . '(' . $this->pMaybeMultiline($node->args) . ')';
    }

    protected function pExpr_Clone(Expr\Clone_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\Clone_::class, 'clone ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Ternary(Expr\Ternary $node, int $precedence, int $lhsPrecedence): string {
        // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.
        // this is okay because the part between ? and : never needs parentheses.
        return $this->pInfixOp(Expr\Ternary::class,
            $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else,
            $precedence, $lhsPrecedence
        );
    }

    protected function pExpr_Exit(Expr\Exit_ $node): string {
        $kind = $node->getAttribute('kind', Expr\Exit_::KIND_DIE);
        return ($kind === Expr\Exit_::KIND_EXIT ? 'exit' : 'die')
             . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : '');
    }

    protected function pExpr_Throw(Expr\Throw_ $node, int $precedence, int $lhsPrecedence): string {
        return $this->pPrefixOp(Expr\Throw_::class, 'throw ', $node->expr, $precedence, $lhsPrecedence);
    }

    protected function pExpr_Yield(Expr\Yield_ $node, int $precedence, int $lhsPrecedence): string {
        if ($node->value === null) {
            $opPrecedence = $this->precedenceMap[Expr\Yield_::class][0];
            return $opPrecedence >= $lhsPrecedence ? '(yield)' : 'yield';
        } else {
            if (!$this->phpVersion->supportsYieldWithoutParentheses()) {
                return '(yield ' . $this->pKey($node->key) . $this->p($node->value) . ')';
            }
            return $this->pPrefixOp(
                Expr\Yield_::class, 'yield ' . $this->pKey($node->key),
                $node->value, $precedence, $lhsPrecedence);
        }
    }

    // Declarations

    protected function pStmt_Namespace(Stmt\Namespace_ $node): string {
        if ($this->canUseSemicolonNamespaces) {
            return 'namespace ' . $this->p($node->name) . ';'
                 . $this->nl . $this->pStmts($node->stmts, false);
        } else {
            return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '')
                 . ' {' . $this->pStmts($node->stmts) . $this->nl . '}';
        }
    }

    protected function pStmt_Use(Stmt\Use_ $node): string {
        return 'use ' . $this->pUseType($node->type)
             . $this->pCommaSeparated($node->uses) . ';';
    }

    protected function pStmt_GroupUse(Stmt\GroupUse $node): string {
        return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix)
             . '\{' . $this->pCommaSeparated($node->uses) . '};';
    }

    protected function pUseItem(Node\UseItem $node): string {
        return $this->pUseType($node->type) . $this->p($node->name)
             . (null !== $node->alias ? ' as ' . $node->alias : '');
    }

    protected function pUseType(int $type): string {
        return $type === Stmt\Use_::TYPE_FUNCTION ? 'function '
            : ($type === Stmt\Use_::TYPE_CONSTANT ? 'const ' : '');
    }

    protected function pStmt_Interface(Stmt\Interface_ $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . 'interface ' . $node->name
             . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')
             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Enum(Stmt\Enum_ $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . 'enum ' . $node->name
             . ($node->scalarType ? ' : ' . $this->p($node->scalarType) : '')
             . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Class(Stmt\Class_ $node): string {
        return $this->pClassCommon($node, ' ' . $node->name);
    }

    protected function pStmt_Trait(Stmt\Trait_ $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . 'trait ' . $node->name
             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_EnumCase(Stmt\EnumCase $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . 'case ' . $node->name
             . ($node->expr ? ' = ' . $this->p($node->expr) : '')
             . ';';
    }

    protected function pStmt_TraitUse(Stmt\TraitUse $node): string {
        return 'use ' . $this->pCommaSeparated($node->traits)
             . (empty($node->adaptations)
                ? ';'
                : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}');
    }

    protected function pStmt_TraitUseAdaptation_Precedence(Stmt\TraitUseAdaptation\Precedence $node): string {
        return $this->p($node->trait) . '::' . $node->method
             . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';';
    }

    protected function pStmt_TraitUseAdaptation_Alias(Stmt\TraitUseAdaptation\Alias $node): string {
        return (null !== $node->trait ? $this->p($node->trait) . '::' : '')
             . $node->method . ' as'
             . (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '')
             . (null !== $node->newName ? ' ' . $node->newName : '')
             . ';';
    }

    protected function pStmt_Property(Stmt\Property $node): string {
        return $this->pAttrGroups($node->attrGroups)
            . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags))
            . ($node->type ? $this->p($node->type) . ' ' : '')
            . $this->pCommaSeparated($node->props) . ';';
    }

    protected function pPropertyItem(Node\PropertyItem $node): string {
        return '$' . $node->name
             . (null !== $node->default ? ' = ' . $this->p($node->default) : '');
    }

    protected function pStmt_ClassMethod(Stmt\ClassMethod $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . $this->pModifiers($node->flags)
             . 'function ' . ($node->byRef ? '&' : '') . $node->name
             . '(' . $this->pMaybeMultiline($node->params, $this->phpVersion->supportsTrailingCommaInParamList()) . ')'
             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')
             . (null !== $node->stmts
                ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'
                : ';');
    }

    protected function pStmt_ClassConst(Stmt\ClassConst $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . $this->pModifiers($node->flags)
             . 'const '
             . (null !== $node->type ? $this->p($node->type) . ' ' : '')
             . $this->pCommaSeparated($node->consts) . ';';
    }

    protected function pStmt_Function(Stmt\Function_ $node): string {
        return $this->pAttrGroups($node->attrGroups)
             . 'function ' . ($node->byRef ? '&' : '') . $node->name
             . '(' . $this->pMaybeMultiline($node->params, $this->phpVersion->supportsTrailingCommaInParamList()) . ')'
             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')
             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Const(Stmt\Const_ $node): string {
        return 'const ' . $this->pCommaSeparated($node->consts) . ';';
    }

    protected function pStmt_Declare(Stmt\Declare_ $node): string {
        return 'declare (' . $this->pCommaSeparated($node->declares) . ')'
             . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';');
    }

    protected function pDeclareItem(Node\DeclareItem $node): string {
        return $node->key . '=' . $this->p($node->value);
    }

    // Control flow

    protected function pStmt_If(Stmt\If_ $node): string {
        return 'if (' . $this->p($node->cond) . ') {'
             . $this->pStmts($node->stmts) . $this->nl . '}'
             . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '')
             . (null !== $node->else ? ' ' . $this->p($node->else) : '');
    }

    protected function pStmt_ElseIf(Stmt\ElseIf_ $node): string {
        return 'elseif (' . $this->p($node->cond) . ') {'
             . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Else(Stmt\Else_ $node): string {
        if (\count($node->stmts) === 1 && $node->stmts[0] instanceof Stmt\If_) {
            // Print as "else if" rather than "else { if }"
            return 'else ' . $this->p($node->stmts[0]);
        }
        return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_For(Stmt\For_ $node): string {
        return 'for ('
             . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '')
             . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '')
             . $this->pCommaSeparated($node->loop)
             . ') {' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Foreach(Stmt\Foreach_ $node): string {
        return 'foreach (' . $this->p($node->expr) . ' as '
             . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')
             . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'
             . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_While(Stmt\While_ $node): string {
        return 'while (' . $this->p($node->cond) . ') {'
             . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Do(Stmt\Do_ $node): string {
        return 'do {' . $this->pStmts($node->stmts) . $this->nl
             . '} while (' . $this->p($node->cond) . ');';
    }

    protected function pStmt_Switch(Stmt\Switch_ $node): string {
        return 'switch (' . $this->p($node->cond) . ') {'
             . $this->pStmts($node->cases) . $this->nl . '}';
    }

    protected function pStmt_Case(Stmt\Case_ $node): string {
        return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'
             . $this->pStmts($node->stmts);
    }

    protected function pStmt_TryCatch(Stmt\TryCatch $node): string {
        return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}'
             . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '')
             . ($node->finally !== null ? ' ' . $this->p($node->finally) : '');
    }

    protected function pStmt_Catch(Stmt\Catch_ $node): string {
        return 'catch (' . $this->pImplode($node->types, '|')
             . ($node->var !== null ? ' ' . $this->p($node->var) : '')
             . ') {' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Finally(Stmt\Finally_ $node): string {
        return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pStmt_Break(Stmt\Break_ $node): string {
        return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
    }

    protected function pStmt_Continue(Stmt\Continue_ $node): string {
        return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';
    }

    protected function pStmt_Return(Stmt\Return_ $node): string {
        return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';';
    }

    protected function pStmt_Label(Stmt\Label $node): string {
        return $node->name . ':';
    }

    protected function pStmt_Goto(Stmt\Goto_ $node): string {
        return 'goto ' . $node->name . ';';
    }

    // Other

    protected function pStmt_Expression(Stmt\Expression $node): string {
        return $this->p($node->expr) . ';';
    }

    protected function pStmt_Echo(Stmt\Echo_ $node): string {
        return 'echo ' . $this->pCommaSeparated($node->exprs) . ';';
    }

    protected function pStmt_Static(Stmt\Static_ $node): string {
        return 'static ' . $this->pCommaSeparated($node->vars) . ';';
    }

    protected function pStmt_Global(Stmt\Global_ $node): string {
        return 'global ' . $this->pCommaSeparated($node->vars) . ';';
    }

    protected function pStaticVar(Node\StaticVar $node): string {
        return $this->p($node->var)
             . (null !== $node->default ? ' = ' . $this->p($node->default) : '');
    }

    protected function pStmt_Unset(Stmt\Unset_ $node): string {
        return 'unset(' . $this->pCommaSeparated($node->vars) . ');';
    }

    protected function pStmt_InlineHTML(Stmt\InlineHTML $node): string {
        $newline = $node->getAttribute('hasLeadingNewline', true) ? $this->newline : '';
        return '?>' . $newline . $node->value . '<?php ';
    }

    protected function pStmt_HaltCompiler(Stmt\HaltCompiler $node): string {
        return '__halt_compiler();' . $node->remaining;
    }

    protected function pStmt_Nop(Stmt\Nop $node): string {
        return '';
    }

    protected function pStmt_Block(Stmt\Block $node): string {
        return '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    // Helpers

    protected function pClassCommon(Stmt\Class_ $node, string $afterClassToken): string {
        return $this->pAttrGroups($node->attrGroups, $node->name === null)
            . $this->pModifiers($node->flags)
            . 'class' . $afterClassToken
            . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')
            . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')
            . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';
    }

    protected function pObjectProperty(Node $node): string {
        if ($node instanceof Expr) {
            return '{' . $this->p($node) . '}';
        } else {
            assert($node instanceof Node\Identifier);
            return $node->name;
        }
    }

    /** @param (Expr|Node\InterpolatedStringPart)[] $encapsList */
    protected function pEncapsList(array $encapsList, ?string $quote): string {
        $return = '';
        foreach ($encapsList as $element) {
            if ($element instanceof Node\InterpolatedStringPart) {
                $return .= $this->escapeString($element->value, $quote);
            } else {
                $return .= '{' . $this->p($element) . '}';
            }
        }

        return $return;
    }

    protected function pSingleQuotedString(string $string): string {
        // It is idiomatic to only escape backslashes when necessary, i.e. when followed by ', \ or
        // the end of the string ('Foo\Bar' instead of 'Foo\\Bar'). However, we also don't want to
        // produce an odd number of backslashes, so '\\\\a' should not get rendered as '\\\a', even
        // though that would be legal.
        $regex = '/\'|\\\\(?=[\'\\\\]|$)|(?<=\\\\)\\\\/';
        return '\'' . preg_replace($regex, '\\\\$0', $string) . '\'';
    }

    protected function escapeString(string $string, ?string $quote): string {
        if (null === $quote) {
            // For doc strings, don't escape newlines
            $escaped = addcslashes($string, "\t\f\v$\\");
            // But do escape isolated \r. Combined with the terminating newline, it might get
            // interpreted as \r\n and dropped from the string contents.
            $escaped = preg_replace('/\r(?!\n)/', '\\r', $escaped);
            if ($this->phpVersion->supportsFlexibleHeredoc()) {
                $escaped = $this->indentString($escaped);
            }
        } else {
            $escaped = addcslashes($string, "\n\r\t\f\v$" . $quote . "\\");
        }

        // Escape control characters and non-UTF-8 characters.
        // Regex based on https://stackoverflow.com/a/11709412/385378.
        $regex = '/(
              [\x00-\x08\x0E-\x1F] # Control characters
            | [\xC0-\xC1] # Invalid UTF-8 Bytes
            | [\xF5-\xFF] # Invalid UTF-8 Bytes
            | \xE0(?=[\x80-\x9F]) # Overlong encoding of prior code point
            | \xF0(?=[\x80-\x8F]) # Overlong encoding of prior code point
            | [\xC2-\xDF](?![\x80-\xBF]) # Invalid UTF-8 Sequence Start
            | [\xE0-\xEF](?![\x80-\xBF]{2}) # Invalid UTF-8 Sequence Start
            | [\xF0-\xF4](?![\x80-\xBF]{3}) # Invalid UTF-8 Sequence Start
            | (?<=[\x00-\x7F\xF5-\xFF])[\x80-\xBF] # Invalid UTF-8 Sequence Middle
            | (?<![\xC2-\xDF]|[\xE0-\xEF]|[\xE0-\xEF][\x80-\xBF]|[\xF0-\xF4]|[\xF0-\xF4][\x80-\xBF]|[\xF0-\xF4][\x80-\xBF]{2})[\x80-\xBF] # Overlong Sequence
            | (?<=[\xE0-\xEF])[\x80-\xBF](?![\x80-\xBF]) # Short 3 byte sequence
            | (?<=[\xF0-\xF4])[\x80-\xBF](?![\x80-\xBF]{2}) # Short 4 byte sequence
            | (?<=[\xF0-\xF4][\x80-\xBF])[\x80-\xBF](?![\x80-\xBF]) # Short 4 byte sequence (2)
        )/x';
        return preg_replace_callback($regex, function ($matches): string {
            assert(strlen($matches[0]) === 1);
            $hex = dechex(ord($matches[0]));
            return '\\x' . str_pad($hex, 2, '0', \STR_PAD_LEFT);
        }, $escaped);
    }

    protected function containsEndLabel(string $string, string $label, bool $atStart = true): bool {
        $start = $atStart ? '(?:^|[\r\n])[ \t]*' : '[\r\n][ \t]*';
        return false !== strpos($string, $label)
            && preg_match('/' . $start . $label . '(?:$|[^_A-Za-z0-9\x80-\xff])/', $string);
    }

    /** @param (Expr|Node\InterpolatedStringPart)[] $parts */
    protected function encapsedContainsEndLabel(array $parts, string $label): bool {
        foreach ($parts as $i => $part) {
            if ($part instanceof Node\InterpolatedStringPart
                && $this->containsEndLabel($this->escapeString($part->value, null), $label, $i === 0)
            ) {
                return true;
            }
        }
        return false;
    }

    protected function pDereferenceLhs(Node $node): string {
        if (!$this->dereferenceLhsRequiresParens($node)) {
            return $this->p($node);
        } else {
            return '(' . $this->p($node) . ')';
        }
    }

    protected function pStaticDereferenceLhs(Node $node): string {
        if (!$this->staticDereferenceLhsRequiresParens($node)) {
            return $this->p($node);
        } else {
            return '(' . $this->p($node) . ')';
        }
    }

    protected function pCallLhs(Node $node): string {
        if (!$this->callLhsRequiresParens($node)) {
            return $this->p($node);
        } else {
            return '(' . $this->p($node) . ')';
        }
    }

    protected function pNewOperand(Node $node): string {
        if (!$this->newOperandRequiresParens($node)) {
            return $this->p($node);
        } else {
            return '(' . $this->p($node) . ')';
        }
    }

    /**
     * @param Node[] $nodes
     */
    protected function hasNodeWithComments(array $nodes): bool {
        foreach ($nodes as $node) {
            if ($node && $node->getComments()) {
                return true;
            }
        }
        return false;
    }

    /** @param Node[] $nodes */
    protected function pMaybeMultiline(array $nodes, bool $trailingComma = false): string {
        if (!$this->hasNodeWithComments($nodes)) {
            return $this->pCommaSeparated($nodes);
        } else {
            return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl;
        }
    }

    /** @param Node\AttributeGroup[] $nodes */
    protected function pAttrGroups(array $nodes, bool $inline = false): string {
        $result = '';
        $sep = $inline ? ' ' : $this->nl;
        foreach ($nodes as $node) {
            $result .= $this->p($node) . $sep;
        }

        return $result;
    }
}
ConstExprEvaluator.php000064400000022330151520657540011077 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\Expr;
use PhpParser\Node\Scalar;

use function array_merge;

/**
 * Evaluates constant expressions.
 *
 * This evaluator is able to evaluate all constant expressions (as defined by PHP), which can be
 * evaluated without further context. If a subexpression is not of this type, a user-provided
 * fallback evaluator is invoked. To support all constant expressions that are also supported by
 * PHP (and not already handled by this class), the fallback evaluator must be able to handle the
 * following node types:
 *
 *  * All Scalar\MagicConst\* nodes.
 *  * Expr\ConstFetch nodes. Only null/false/true are already handled by this class.
 *  * Expr\ClassConstFetch nodes.
 *
 * The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate.
 *
 * The evaluation is dependent on runtime configuration in two respects: Firstly, floating
 * point to string conversions are affected by the precision ini setting. Secondly, they are also
 * affected by the LC_NUMERIC locale.
 */
class ConstExprEvaluator {
    /** @var callable|null */
    private $fallbackEvaluator;

    /**
     * Create a constant expression evaluator.
     *
     * The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See
     * class doc comment for more information.
     *
     * @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated
     */
    public function __construct(?callable $fallbackEvaluator = null) {
        $this->fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) {
            throw new ConstExprEvaluationException(
                "Expression of type {$expr->getType()} cannot be evaluated"
            );
        };
    }

    /**
     * Silently evaluates a constant expression into a PHP value.
     *
     * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.
     * The original source of the exception is available through getPrevious().
     *
     * If some part of the expression cannot be evaluated, the fallback evaluator passed to the
     * constructor will be invoked. By default, if no fallback is provided, an exception of type
     * ConstExprEvaluationException is thrown.
     *
     * See class doc comment for caveats and limitations.
     *
     * @param Expr $expr Constant expression to evaluate
     * @return mixed Result of evaluation
     *
     * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred
     */
    public function evaluateSilently(Expr $expr) {
        set_error_handler(function ($num, $str, $file, $line) {
            throw new \ErrorException($str, 0, $num, $file, $line);
        });

        try {
            return $this->evaluate($expr);
        } catch (\Throwable $e) {
            if (!$e instanceof ConstExprEvaluationException) {
                $e = new ConstExprEvaluationException(
                    "An error occurred during constant expression evaluation", 0, $e);
            }
            throw $e;
        } finally {
            restore_error_handler();
        }
    }

    /**
     * Directly evaluates a constant expression into a PHP value.
     *
     * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these
     * into a ConstExprEvaluationException.
     *
     * If some part of the expression cannot be evaluated, the fallback evaluator passed to the
     * constructor will be invoked. By default, if no fallback is provided, an exception of type
     * ConstExprEvaluationException is thrown.
     *
     * See class doc comment for caveats and limitations.
     *
     * @param Expr $expr Constant expression to evaluate
     * @return mixed Result of evaluation
     *
     * @throws ConstExprEvaluationException if the expression cannot be evaluated
     */
    public function evaluateDirectly(Expr $expr) {
        return $this->evaluate($expr);
    }

    /** @return mixed */
    private function evaluate(Expr $expr) {
        if ($expr instanceof Scalar\Int_
            || $expr instanceof Scalar\Float_
            || $expr instanceof Scalar\String_
        ) {
            return $expr->value;
        }

        if ($expr instanceof Expr\Array_) {
            return $this->evaluateArray($expr);
        }

        // Unary operators
        if ($expr instanceof Expr\UnaryPlus) {
            return +$this->evaluate($expr->expr);
        }
        if ($expr instanceof Expr\UnaryMinus) {
            return -$this->evaluate($expr->expr);
        }
        if ($expr instanceof Expr\BooleanNot) {
            return !$this->evaluate($expr->expr);
        }
        if ($expr instanceof Expr\BitwiseNot) {
            return ~$this->evaluate($expr->expr);
        }

        if ($expr instanceof Expr\BinaryOp) {
            return $this->evaluateBinaryOp($expr);
        }

        if ($expr instanceof Expr\Ternary) {
            return $this->evaluateTernary($expr);
        }

        if ($expr instanceof Expr\ArrayDimFetch && null !== $expr->dim) {
            return $this->evaluate($expr->var)[$this->evaluate($expr->dim)];
        }

        if ($expr instanceof Expr\ConstFetch) {
            return $this->evaluateConstFetch($expr);
        }

        return ($this->fallbackEvaluator)($expr);
    }

    private function evaluateArray(Expr\Array_ $expr): array {
        $array = [];
        foreach ($expr->items as $item) {
            if (null !== $item->key) {
                $array[$this->evaluate($item->key)] = $this->evaluate($item->value);
            } elseif ($item->unpack) {
                $array = array_merge($array, $this->evaluate($item->value));
            } else {
                $array[] = $this->evaluate($item->value);
            }
        }
        return $array;
    }

    /** @return mixed */
    private function evaluateTernary(Expr\Ternary $expr) {
        if (null === $expr->if) {
            return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else);
        }

        return $this->evaluate($expr->cond)
            ? $this->evaluate($expr->if)
            : $this->evaluate($expr->else);
    }

    /** @return mixed */
    private function evaluateBinaryOp(Expr\BinaryOp $expr) {
        if ($expr instanceof Expr\BinaryOp\Coalesce
            && $expr->left instanceof Expr\ArrayDimFetch
        ) {
            // This needs to be special cased to respect BP_VAR_IS fetch semantics
            return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]
                ?? $this->evaluate($expr->right);
        }

        // The evaluate() calls are repeated in each branch, because some of the operators are
        // short-circuiting and evaluating the RHS in advance may be illegal in that case
        $l = $expr->left;
        $r = $expr->right;
        switch ($expr->getOperatorSigil()) {
            case '&':   return $this->evaluate($l) &   $this->evaluate($r);
            case '|':   return $this->evaluate($l) |   $this->evaluate($r);
            case '^':   return $this->evaluate($l) ^   $this->evaluate($r);
            case '&&':  return $this->evaluate($l) &&  $this->evaluate($r);
            case '||':  return $this->evaluate($l) ||  $this->evaluate($r);
            case '??':  return $this->evaluate($l) ??  $this->evaluate($r);
            case '.':   return $this->evaluate($l) .   $this->evaluate($r);
            case '/':   return $this->evaluate($l) /   $this->evaluate($r);
            case '==':  return $this->evaluate($l) ==  $this->evaluate($r);
            case '>':   return $this->evaluate($l) >   $this->evaluate($r);
            case '>=':  return $this->evaluate($l) >=  $this->evaluate($r);
            case '===': return $this->evaluate($l) === $this->evaluate($r);
            case 'and': return $this->evaluate($l) and $this->evaluate($r);
            case 'or':  return $this->evaluate($l) or  $this->evaluate($r);
            case 'xor': return $this->evaluate($l) xor $this->evaluate($r);
            case '-':   return $this->evaluate($l) -   $this->evaluate($r);
            case '%':   return $this->evaluate($l) %   $this->evaluate($r);
            case '*':   return $this->evaluate($l) *   $this->evaluate($r);
            case '!=':  return $this->evaluate($l) !=  $this->evaluate($r);
            case '!==': return $this->evaluate($l) !== $this->evaluate($r);
            case '+':   return $this->evaluate($l) +   $this->evaluate($r);
            case '**':  return $this->evaluate($l) **  $this->evaluate($r);
            case '<<':  return $this->evaluate($l) <<  $this->evaluate($r);
            case '>>':  return $this->evaluate($l) >>  $this->evaluate($r);
            case '<':   return $this->evaluate($l) <   $this->evaluate($r);
            case '<=':  return $this->evaluate($l) <=  $this->evaluate($r);
            case '<=>': return $this->evaluate($l) <=> $this->evaluate($r);
        }

        throw new \Exception('Should not happen');
    }

    /** @return mixed */
    private function evaluateConstFetch(Expr\ConstFetch $expr) {
        $name = $expr->name->toLowerString();
        switch ($name) {
            case 'null': return null;
            case 'false': return false;
            case 'true': return true;
        }

        return ($this->fallbackEvaluator)($expr);
    }
}
Parser.php000064400000001375151520657540006531 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface Parser {
    /**
     * Parses PHP code into a node tree.
     *
     * @param string $code The source code to parse
     * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults
     *                                        to ErrorHandler\Throwing.
     *
     * @return Node\Stmt[]|null Array of statements (or null non-throwing error handler is used and
     *                          the parser was unable to recover from an error).
     */
    public function parse(string $code, ?ErrorHandler $errorHandler = null): ?array;

    /**
     * Return tokens for the last parse.
     *
     * @return Token[]
     */
    public function getTokens(): array;
}
NodeVisitor/NodeConnectingVisitor.php000064400000002566151520657540014022 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;

/**
 * Visitor that connects a child node to its parent node
 * as well as its sibling nodes.
 *
 * On the child node, the parent node can be accessed through
 * <code>$node->getAttribute('parent')</code>, the previous
 * node can be accessed through <code>$node->getAttribute('previous')</code>,
 * and the next node can be accessed through <code>$node->getAttribute('next')</code>.
 */
final class NodeConnectingVisitor extends NodeVisitorAbstract {
    /**
     * @var Node[]
     */
    private array $stack = [];

    /**
     * @var ?Node
     */
    private $previous;

    public function beforeTraverse(array $nodes) {
        $this->stack    = [];
        $this->previous = null;
    }

    public function enterNode(Node $node) {
        if (!empty($this->stack)) {
            $node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
        }

        if ($this->previous !== null && $this->previous->getAttribute('parent') === $node->getAttribute('parent')) {
            $node->setAttribute('previous', $this->previous);
            $this->previous->setAttribute('next', $node);
        }

        $this->stack[] = $node;
    }

    public function leaveNode(Node $node) {
        $this->previous = $node;

        array_pop($this->stack);
    }
}
NodeVisitor/NameResolver.php000064400000023477151520657540012153 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\ErrorHandler;
use PhpParser\NameContext;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt;
use PhpParser\NodeVisitorAbstract;

class NameResolver extends NodeVisitorAbstract {
    /** @var NameContext Naming context */
    protected NameContext $nameContext;

    /** @var bool Whether to preserve original names */
    protected bool $preserveOriginalNames;

    /** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */
    protected bool $replaceNodes;

    /**
     * Constructs a name resolution visitor.
     *
     * Options:
     *  * preserveOriginalNames (default false): An "originalName" attribute will be added to
     *    all name nodes that underwent resolution.
     *  * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a
     *    resolvedName attribute is added. (Names that cannot be statically resolved receive a
     *    namespacedName attribute, as usual.)
     *
     * @param ErrorHandler|null $errorHandler Error handler
     * @param array{preserveOriginalNames?: bool, replaceNodes?: bool} $options Options
     */
    public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {
        $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\Throwing());
        $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;
        $this->replaceNodes = $options['replaceNodes'] ?? true;
    }

    /**
     * Get name resolution context.
     */
    public function getNameContext(): NameContext {
        return $this->nameContext;
    }

    public function beforeTraverse(array $nodes): ?array {
        $this->nameContext->startNamespace();
        return null;
    }

    public function enterNode(Node $node) {
        if ($node instanceof Stmt\Namespace_) {
            $this->nameContext->startNamespace($node->name);
        } elseif ($node instanceof Stmt\Use_) {
            foreach ($node->uses as $use) {
                $this->addAlias($use, $node->type, null);
            }
        } elseif ($node instanceof Stmt\GroupUse) {
            foreach ($node->uses as $use) {
                $this->addAlias($use, $node->type, $node->prefix);
            }
        } elseif ($node instanceof Stmt\Class_) {
            if (null !== $node->extends) {
                $node->extends = $this->resolveClassName($node->extends);
            }

            foreach ($node->implements as &$interface) {
                $interface = $this->resolveClassName($interface);
            }

            $this->resolveAttrGroups($node);
            if (null !== $node->name) {
                $this->addNamespacedName($node);
            } else {
                $node->namespacedName = null;
            }
        } elseif ($node instanceof Stmt\Interface_) {
            foreach ($node->extends as &$interface) {
                $interface = $this->resolveClassName($interface);
            }

            $this->resolveAttrGroups($node);
            $this->addNamespacedName($node);
        } elseif ($node instanceof Stmt\Enum_) {
            foreach ($node->implements as &$interface) {
                $interface = $this->resolveClassName($interface);
            }

            $this->resolveAttrGroups($node);
            $this->addNamespacedName($node);
        } elseif ($node instanceof Stmt\Trait_) {
            $this->resolveAttrGroups($node);
            $this->addNamespacedName($node);
        } elseif ($node instanceof Stmt\Function_) {
            $this->resolveSignature($node);
            $this->resolveAttrGroups($node);
            $this->addNamespacedName($node);
        } elseif ($node instanceof Stmt\ClassMethod
                  || $node instanceof Expr\Closure
                  || $node instanceof Expr\ArrowFunction
        ) {
            $this->resolveSignature($node);
            $this->resolveAttrGroups($node);
        } elseif ($node instanceof Stmt\Property) {
            if (null !== $node->type) {
                $node->type = $this->resolveType($node->type);
            }
            $this->resolveAttrGroups($node);
        } elseif ($node instanceof Stmt\Const_) {
            foreach ($node->consts as $const) {
                $this->addNamespacedName($const);
            }
        } elseif ($node instanceof Stmt\ClassConst) {
            if (null !== $node->type) {
                $node->type = $this->resolveType($node->type);
            }
            $this->resolveAttrGroups($node);
        } elseif ($node instanceof Stmt\EnumCase) {
            $this->resolveAttrGroups($node);
        } elseif ($node instanceof Expr\StaticCall
                  || $node instanceof Expr\StaticPropertyFetch
                  || $node instanceof Expr\ClassConstFetch
                  || $node instanceof Expr\New_
                  || $node instanceof Expr\Instanceof_
        ) {
            if ($node->class instanceof Name) {
                $node->class = $this->resolveClassName($node->class);
            }
        } elseif ($node instanceof Stmt\Catch_) {
            foreach ($node->types as &$type) {
                $type = $this->resolveClassName($type);
            }
        } elseif ($node instanceof Expr\FuncCall) {
            if ($node->name instanceof Name) {
                $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_FUNCTION);
            }
        } elseif ($node instanceof Expr\ConstFetch) {
            $node->name = $this->resolveName($node->name, Stmt\Use_::TYPE_CONSTANT);
        } elseif ($node instanceof Stmt\TraitUse) {
            foreach ($node->traits as &$trait) {
                $trait = $this->resolveClassName($trait);
            }

            foreach ($node->adaptations as $adaptation) {
                if (null !== $adaptation->trait) {
                    $adaptation->trait = $this->resolveClassName($adaptation->trait);
                }

                if ($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) {
                    foreach ($adaptation->insteadof as &$insteadof) {
                        $insteadof = $this->resolveClassName($insteadof);
                    }
                }
            }
        }

        return null;
    }

    /** @param Stmt\Use_::TYPE_* $type */
    private function addAlias(Node\UseItem $use, int $type, ?Name $prefix = null): void {
        // Add prefix for group uses
        $name = $prefix ? Name::concat($prefix, $use->name) : $use->name;
        // Type is determined either by individual element or whole use declaration
        $type |= $use->type;

        $this->nameContext->addAlias(
            $name, (string) $use->getAlias(), $type, $use->getAttributes()
        );
    }

    /** @param Stmt\Function_|Stmt\ClassMethod|Expr\Closure|Expr\ArrowFunction $node */
    private function resolveSignature($node): void {
        foreach ($node->params as $param) {
            $param->type = $this->resolveType($param->type);
            $this->resolveAttrGroups($param);
        }
        $node->returnType = $this->resolveType($node->returnType);
    }

    /**
     * @template T of Node\Identifier|Name|Node\ComplexType|null
     * @param T $node
     * @return T
     */
    private function resolveType(?Node $node): ?Node {
        if ($node instanceof Name) {
            return $this->resolveClassName($node);
        }
        if ($node instanceof Node\NullableType) {
            $node->type = $this->resolveType($node->type);
            return $node;
        }
        if ($node instanceof Node\UnionType || $node instanceof Node\IntersectionType) {
            foreach ($node->types as &$type) {
                $type = $this->resolveType($type);
            }
            return $node;
        }
        return $node;
    }

    /**
     * Resolve name, according to name resolver options.
     *
     * @param Name $name Function or constant name to resolve
     * @param Stmt\Use_::TYPE_* $type One of Stmt\Use_::TYPE_*
     *
     * @return Name Resolved name, or original name with attribute
     */
    protected function resolveName(Name $name, int $type): Name {
        if (!$this->replaceNodes) {
            $resolvedName = $this->nameContext->getResolvedName($name, $type);
            if (null !== $resolvedName) {
                $name->setAttribute('resolvedName', $resolvedName);
            } else {
                $name->setAttribute('namespacedName', FullyQualified::concat(
                    $this->nameContext->getNamespace(), $name, $name->getAttributes()));
            }
            return $name;
        }

        if ($this->preserveOriginalNames) {
            // Save the original name
            $originalName = $name;
            $name = clone $originalName;
            $name->setAttribute('originalName', $originalName);
        }

        $resolvedName = $this->nameContext->getResolvedName($name, $type);
        if (null !== $resolvedName) {
            return $resolvedName;
        }

        // unqualified names inside a namespace cannot be resolved at compile-time
        // add the namespaced version of the name as an attribute
        $name->setAttribute('namespacedName', FullyQualified::concat(
            $this->nameContext->getNamespace(), $name, $name->getAttributes()));
        return $name;
    }

    protected function resolveClassName(Name $name): Name {
        return $this->resolveName($name, Stmt\Use_::TYPE_NORMAL);
    }

    protected function addNamespacedName(Node $node): void {
        $node->namespacedName = Name::concat(
            $this->nameContext->getNamespace(), (string) $node->name);
    }

    protected function resolveAttrGroups(Node $node): void {
        foreach ($node->attrGroups as $attrGroup) {
            foreach ($attrGroup->attrs as $attr) {
                $attr->name = $this->resolveClassName($attr->name);
            }
        }
    }
}
NodeVisitor/ParentConnectingVisitor.php000064400000001534151520657540014360 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;

use function array_pop;
use function count;

/**
 * Visitor that connects a child node to its parent node.
 *
 * On the child node, the parent node can be accessed through
 * <code>$node->getAttribute('parent')</code>.
 */
final class ParentConnectingVisitor extends NodeVisitorAbstract {
    /**
     * @var Node[]
     */
    private array $stack = [];

    public function beforeTraverse(array $nodes) {
        $this->stack = [];
    }

    public function enterNode(Node $node) {
        if (!empty($this->stack)) {
            $node->setAttribute('parent', $this->stack[count($this->stack) - 1]);
        }

        $this->stack[] = $node;
    }

    public function leaveNode(Node $node) {
        array_pop($this->stack);
    }
}
NodeVisitor/FirstFindingVisitor.php000064400000002343151520657540013504 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitor;
use PhpParser\NodeVisitorAbstract;

/**
 * This visitor can be used to find the first node satisfying some criterion determined by
 * a filter callback.
 */
class FirstFindingVisitor extends NodeVisitorAbstract {
    /** @var callable Filter callback */
    protected $filterCallback;
    /** @var null|Node Found node */
    protected ?Node $foundNode;

    public function __construct(callable $filterCallback) {
        $this->filterCallback = $filterCallback;
    }

    /**
     * Get found node satisfying the filter callback.
     *
     * Returns null if no node satisfies the filter callback.
     *
     * @return null|Node Found node (or null if not found)
     */
    public function getFoundNode(): ?Node {
        return $this->foundNode;
    }

    public function beforeTraverse(array $nodes): ?array {
        $this->foundNode = null;

        return null;
    }

    public function enterNode(Node $node) {
        $filterCallback = $this->filterCallback;
        if ($filterCallback($node)) {
            $this->foundNode = $node;
            return NodeVisitor::STOP_TRAVERSAL;
        }

        return null;
    }
}
NodeVisitor/FindingVisitor.php000064400000002157151520657540012477 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;

/**
 * This visitor can be used to find and collect all nodes satisfying some criterion determined by
 * a filter callback.
 */
class FindingVisitor extends NodeVisitorAbstract {
    /** @var callable Filter callback */
    protected $filterCallback;
    /** @var Node[] Found nodes */
    protected array $foundNodes;

    public function __construct(callable $filterCallback) {
        $this->filterCallback = $filterCallback;
    }

    /**
     * Get found nodes satisfying the filter callback.
     *
     * Nodes are returned in pre-order.
     *
     * @return Node[] Found nodes
     */
    public function getFoundNodes(): array {
        return $this->foundNodes;
    }

    public function beforeTraverse(array $nodes): ?array {
        $this->foundNodes = [];

        return null;
    }

    public function enterNode(Node $node) {
        $filterCallback = $this->filterCallback;
        if ($filterCallback($node)) {
            $this->foundNodes[] = $node;
        }

        return null;
    }
}
NodeVisitor/CloningVisitor.php000064400000000766151520657540012516 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;

/**
 * Visitor cloning all nodes and linking to the original nodes using an attribute.
 *
 * This visitor is required to perform format-preserving pretty prints.
 */
class CloningVisitor extends NodeVisitorAbstract {
    public function enterNode(Node $origNode) {
        $node = clone $origNode;
        $node->setAttribute('origNode', $origNode);
        return $node;
    }
}
NodeVisitor/CommentAnnotatingVisitor.php000064400000005331151520657540014543 0ustar00<?php declare(strict_types=1);

namespace PhpParser\NodeVisitor;

use PhpParser\Comment;
use PhpParser\Node;
use PhpParser\NodeVisitorAbstract;
use PhpParser\Token;

class CommentAnnotatingVisitor extends NodeVisitorAbstract {
    /** @var int Last seen token start position */
    private int $pos = 0;
    /** @var Token[] Token array */
    private array $tokens;
    /** @var list<int> Token positions of comments */
    private array $commentPositions = [];

    /**
     * Create a comment annotation visitor.
     *
     * @param Token[] $tokens Token array
     */
    public function __construct(array $tokens) {
        $this->tokens = $tokens;

        // Collect positions of comments. We use this to avoid traversing parts of the AST where
        // there are no comments.
        foreach ($tokens as $i => $token) {
            if ($token->id === \T_COMMENT || $token->id === \T_DOC_COMMENT) {
                $this->commentPositions[] = $i;
            }
        }
    }

    public function enterNode(Node $node) {
        $nextCommentPos = current($this->commentPositions);
        if ($nextCommentPos === false) {
            // No more comments.
            return self::STOP_TRAVERSAL;
        }

        $oldPos = $this->pos;
        $this->pos = $pos = $node->getStartTokenPos();
        if ($nextCommentPos > $oldPos && $nextCommentPos < $pos) {
            $comments = [];
            while (--$pos >= $oldPos) {
                $token = $this->tokens[$pos];
                if ($token->id === \T_DOC_COMMENT) {
                    $comments[] = new Comment\Doc(
                        $token->text, $token->line, $token->pos, $pos,
                        $token->getEndLine(), $token->getEndPos() - 1, $pos);
                    continue;
                }
                if ($token->id === \T_COMMENT) {
                    $comments[] = new Comment(
                        $token->text, $token->line, $token->pos, $pos,
                        $token->getEndLine(), $token->getEndPos() - 1, $pos);
                    continue;
                }
                if ($token->id !== \T_WHITESPACE) {
                    break;
                }
            }
            if (!empty($comments)) {
                $node->setAttribute('comments', array_reverse($comments));
            }

            do {
                $nextCommentPos = next($this->commentPositions);
            } while ($nextCommentPos !== false && $nextCommentPos < $this->pos);
        }

        $endPos = $node->getEndTokenPos();
        if ($nextCommentPos > $endPos) {
            // Skip children if there are no comments located inside this node.
            $this->pos = $endPos;
            return self::DONT_TRAVERSE_CHILDREN;
        }

        return null;
    }
}
Node/AttributeGroup.php000064400000001207151520657540011134 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class AttributeGroup extends NodeAbstract {
    /** @var Attribute[] Attributes */
    public array $attrs;

    /**
     * @param Attribute[] $attrs PHP attributes
     * @param array<string, mixed> $attributes Additional node attributes
     */
    public function __construct(array $attrs, array $attributes = []) {
        $this->attributes = $attributes;
        $this->attrs = $attrs;
    }

    public function getSubNodeNames(): array {
        return ['attrs'];
    }

    public function getType(): string {
        return 'AttributeGroup';
    }
}
Node/Identifier.php000064400000003430151520657540010236 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

/**
 * Represents a non-namespaced name. Namespaced names are represented using Name nodes.
 */
class Identifier extends NodeAbstract {
    /** @var string Identifier as string */
    public string $name;

    /** @var array<string, bool> */
    private static array $specialClassNames = [
        'self'   => true,
        'parent' => true,
        'static' => true,
    ];

    /**
     * Constructs an identifier node.
     *
     * @param string $name Identifier as string
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(string $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    /**
     * Get identifier as string.
     *
     * @return string Identifier as string.
     */
    public function toString(): string {
        return $this->name;
    }

    /**
     * Get lowercased identifier as string.
     *
     * @return string Lowercased identifier as string
     */
    public function toLowerString(): string {
        return strtolower($this->name);
    }

    /**
     * Checks whether the identifier is a special class name (self, parent or static).
     *
     * @return bool Whether identifier is a special class name
     */
    public function isSpecialClassName(): bool {
        return isset(self::$specialClassNames[strtolower($this->name)]);
    }

    /**
     * Get identifier as string.
     *
     * @return string Identifier as string
     */
    public function __toString(): string {
        return $this->name;
    }

    public function getType(): string {
        return 'Identifier';
    }
}
Node/UnionType.php000064400000001245151520657540010110 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

class UnionType extends ComplexType {
    /** @var (Identifier|Name|IntersectionType)[] Types */
    public array $types;

    /**
     * Constructs a union type.
     *
     * @param (Identifier|Name|IntersectionType)[] $types Types
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $types, array $attributes = []) {
        $this->attributes = $attributes;
        $this->types = $types;
    }

    public function getSubNodeNames(): array {
        return ['types'];
    }

    public function getType(): string {
        return 'UnionType';
    }
}
Node/ArrayItem.php000064400000002274151520657540010056 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class ArrayItem extends NodeAbstract {
    /** @var null|Expr Key */
    public ?Expr $key;
    /** @var Expr Value */
    public Expr $value;
    /** @var bool Whether to assign by reference */
    public bool $byRef;
    /** @var bool Whether to unpack the argument */
    public bool $unpack;

    /**
     * Constructs an array item node.
     *
     * @param Expr $value Value
     * @param null|Expr $key Key
     * @param bool $byRef Whether to assign by reference
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $value, ?Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {
        $this->attributes = $attributes;
        $this->key = $key;
        $this->value = $value;
        $this->byRef = $byRef;
        $this->unpack = $unpack;
    }

    public function getSubNodeNames(): array {
        return ['key', 'value', 'byRef', 'unpack'];
    }

    public function getType(): string {
        return 'ArrayItem';
    }
}

// @deprecated compatibility alias
class_alias(ArrayItem::class, Expr\ArrayItem::class);
Node/Name/FullyQualified.php000064400000002222151520657540011751 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Name;

class FullyQualified extends \PhpParser\Node\Name {
    /**
     * Checks whether the name is unqualified. (E.g. Name)
     *
     * @return bool Whether the name is unqualified
     */
    public function isUnqualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is qualified. (E.g. Name\Name)
     *
     * @return bool Whether the name is qualified
     */
    public function isQualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is fully qualified. (E.g. \Name)
     *
     * @return bool Whether the name is fully qualified
     */
    public function isFullyQualified(): bool {
        return true;
    }

    /**
     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name)
     *
     * @return bool Whether the name is relative
     */
    public function isRelative(): bool {
        return false;
    }

    public function toCodeString(): string {
        return '\\' . $this->toString();
    }

    public function getType(): string {
        return 'Name_FullyQualified';
    }
}
Node/Name/Relative.php000064400000002217151520657540010611 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Name;

class Relative extends \PhpParser\Node\Name {
    /**
     * Checks whether the name is unqualified. (E.g. Name)
     *
     * @return bool Whether the name is unqualified
     */
    public function isUnqualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is qualified. (E.g. Name\Name)
     *
     * @return bool Whether the name is qualified
     */
    public function isQualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is fully qualified. (E.g. \Name)
     *
     * @return bool Whether the name is fully qualified
     */
    public function isFullyQualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name)
     *
     * @return bool Whether the name is relative
     */
    public function isRelative(): bool {
        return true;
    }

    public function toCodeString(): string {
        return 'namespace\\' . $this->toString();
    }

    public function getType(): string {
        return 'Name_Relative';
    }
}
Node/FunctionLike.php000064400000001333151520657540010546 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;

interface FunctionLike extends Node {
    /**
     * Whether to return by reference
     */
    public function returnsByRef(): bool;

    /**
     * List of parameters
     *
     * @return Param[]
     */
    public function getParams(): array;

    /**
     * Get the declared return type or null
     *
     * @return null|Identifier|Name|ComplexType
     */
    public function getReturnType();

    /**
     * The function body
     *
     * @return Stmt[]|null
     */
    public function getStmts(): ?array;

    /**
     * Get PHP attribute groups.
     *
     * @return AttributeGroup[]
     */
    public function getAttrGroups(): array;
}
Node/Const_.php000064400000001713151520657540007403 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class Const_ extends NodeAbstract {
    /** @var Identifier Name */
    public Identifier $name;
    /** @var Expr Value */
    public Expr $value;

    /** @var Name|null Namespaced name (if using NameResolver) */
    public ?Name $namespacedName;

    /**
     * Constructs a const node for use in class const and const statements.
     *
     * @param string|Identifier $name Name
     * @param Expr $value Value
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, Expr $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['name', 'value'];
    }

    public function getType(): string {
        return 'Const';
    }
}
Node/VarLikeIdentifier.php000064400000000766151520657540011525 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

/**
 * Represents a name that is written in source code with a leading dollar,
 * but is not a proper variable. The leading dollar is not stored as part of the name.
 *
 * Examples: Names in property declarations are formatted as variables. Names in static property
 * lookups are also formatted as variables.
 */
class VarLikeIdentifier extends Identifier {
    public function getType(): string {
        return 'VarLikeIdentifier';
    }
}
Node/StaticVar.php000064400000001747151520657540010065 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;

class StaticVar extends NodeAbstract {
    /** @var Expr\Variable Variable */
    public Expr\Variable $var;
    /** @var null|Node\Expr Default value */
    public ?Expr $default;

    /**
     * Constructs a static variable node.
     *
     * @param Expr\Variable $var Name
     * @param null|Node\Expr $default Default value
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(
        Expr\Variable $var, ?Node\Expr $default = null, array $attributes = []
    ) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->default = $default;
    }

    public function getSubNodeNames(): array {
        return ['var', 'default'];
    }

    public function getType(): string {
        return 'StaticVar';
    }
}

// @deprecated compatibility alias
class_alias(StaticVar::class, Stmt\StaticVar::class);
Node/InterpolatedStringPart.php000064400000001522151520657540012624 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class InterpolatedStringPart extends NodeAbstract {
    /** @var string String value */
    public string $value;

    /**
     * Constructs a node representing a string part of an interpolated string.
     *
     * @param string $value String value
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(string $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['value'];
    }

    public function getType(): string {
        return 'InterpolatedStringPart';
    }
}

// @deprecated compatibility alias
class_alias(InterpolatedStringPart::class, Scalar\EncapsedStringPart::class);
Node/Attribute.php000064400000001464151520657540010124 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;

class Attribute extends NodeAbstract {
    /** @var Name Attribute name */
    public Name $name;

    /** @var list<Arg> Attribute arguments */
    public array $args;

    /**
     * @param Node\Name $name Attribute name
     * @param list<Arg> $args Attribute arguments
     * @param array<string, mixed> $attributes Additional node attributes
     */
    public function __construct(Name $name, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['name', 'args'];
    }

    public function getType(): string {
        return 'Attribute';
    }
}
Node/VariadicPlaceholder.php000064400000001215151520657540012040 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

/**
 * Represents the "..." in "foo(...)" of the first-class callable syntax.
 */
class VariadicPlaceholder extends NodeAbstract {
    /**
     * Create a variadic argument placeholder (first-class callable syntax).
     *
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $attributes = []) {
        $this->attributes = $attributes;
    }

    public function getType(): string {
        return 'VariadicPlaceholder';
    }

    public function getSubNodeNames(): array {
        return [];
    }
}
Node/DeclareItem.php000064400000001740151520657540010334 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;

class DeclareItem extends NodeAbstract {
    /** @var Node\Identifier Key */
    public Identifier $key;
    /** @var Node\Expr Value */
    public Expr $value;

    /**
     * Constructs a declare key=>value pair node.
     *
     * @param string|Node\Identifier $key Key
     * @param Node\Expr $value Value
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($key, Node\Expr $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->key = \is_string($key) ? new Node\Identifier($key) : $key;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['key', 'value'];
    }

    public function getType(): string {
        return 'DeclareItem';
    }
}

// @deprecated compatibility alias
class_alias(DeclareItem::class, Stmt\DeclareDeclare::class);
Node/Stmt/Block.php000064400000001206151520657540010134 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Stmt;

class Block extends Stmt {
    /** @var Stmt[] Statements */
    public array $stmts;

    /**
     * A block of statements.
     *
     * @param Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $stmts, array $attributes = []) {
        $this->attributes = $attributes;
        $this->stmts = $stmts;
    }

    public function getType(): string {
        return 'Stmt_Block';
    }

    public function getSubNodeNames(): array {
        return ['stmts'];
    }
}
Node/Stmt/Unset_.php000064400000001236151520657540010342 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Unset_ extends Node\Stmt {
    /** @var Node\Expr[] Variables to unset */
    public array $vars;

    /**
     * Constructs an unset node.
     *
     * @param Node\Expr[] $vars Variables to unset
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $vars, array $attributes = []) {
        $this->attributes = $attributes;
        $this->vars = $vars;
    }

    public function getSubNodeNames(): array {
        return ['vars'];
    }

    public function getType(): string {
        return 'Stmt_Unset';
    }
}
Node/Stmt/Property.php000064400000004426151520657540010735 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\ComplexType;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\PropertyItem;

class Property extends Node\Stmt {
    /** @var int Modifiers */
    public int $flags;
    /** @var PropertyItem[] Properties */
    public array $props;
    /** @var null|Identifier|Name|ComplexType Type declaration */
    public ?Node $type;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /**
     * Constructs a class property list node.
     *
     * @param int $flags Modifiers
     * @param PropertyItem[] $props Properties
     * @param array<string, mixed> $attributes Additional attributes
     * @param null|Identifier|Name|ComplexType $type Type declaration
     * @param Node\AttributeGroup[] $attrGroups PHP attribute groups
     */
    public function __construct(int $flags, array $props, array $attributes = [], ?Node $type = null, array $attrGroups = []) {
        $this->attributes = $attributes;
        $this->flags = $flags;
        $this->props = $props;
        $this->type = $type;
        $this->attrGroups = $attrGroups;
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'type', 'props'];
    }

    /**
     * Whether the property is explicitly or implicitly public.
     */
    public function isPublic(): bool {
        return ($this->flags & Modifiers::PUBLIC) !== 0
            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;
    }

    /**
     * Whether the property is protected.
     */
    public function isProtected(): bool {
        return (bool) ($this->flags & Modifiers::PROTECTED);
    }

    /**
     * Whether the property is private.
     */
    public function isPrivate(): bool {
        return (bool) ($this->flags & Modifiers::PRIVATE);
    }

    /**
     * Whether the property is static.
     */
    public function isStatic(): bool {
        return (bool) ($this->flags & Modifiers::STATIC);
    }

    /**
     * Whether the property is readonly.
     */
    public function isReadonly(): bool {
        return (bool) ($this->flags & Modifiers::READONLY);
    }

    public function getType(): string {
        return 'Stmt_Property';
    }
}
Node/Stmt/TraitUseAdaptation.php000064400000000445151520657540012653 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

abstract class TraitUseAdaptation extends Node\Stmt {
    /** @var Node\Name|null Trait name */
    public ?Node\Name $trait;
    /** @var Node\Identifier Method name */
    public Node\Identifier $method;
}
Node/Stmt/Const_.php000064400000001270151520657540010330 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Const_ extends Node\Stmt {
    /** @var Node\Const_[] Constant declarations */
    public array $consts;

    /**
     * Constructs a const list node.
     *
     * @param Node\Const_[] $consts Constant declarations
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $consts, array $attributes = []) {
        $this->attributes = $attributes;
        $this->consts = $consts;
    }

    public function getSubNodeNames(): array {
        return ['consts'];
    }

    public function getType(): string {
        return 'Stmt_Const';
    }
}
Node/Stmt/Interface_.php000064400000002455151520657540011150 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Interface_ extends ClassLike {
    /** @var Node\Name[] Extended interfaces */
    public array $extends;

    /**
     * Constructs a class node.
     *
     * @param string|Node\Identifier $name Name
     * @param array{
     *     extends?: Node\Name[],
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'extends'    => array(): Name of extended interfaces
     *             'stmts'      => array(): Statements
     *             'attrGroups' => array(): PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->extends = $subNodes['extends'] ?? [];
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'name', 'extends', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Interface';
    }
}
Node/Stmt/StaticVar.php000064400000000107151520657540011001 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../StaticVar.php';
Node/Stmt/Trait_.php000064400000002057151520657540010331 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Trait_ extends ClassLike {
    /**
     * Constructs a trait node.
     *
     * @param string|Node\Identifier $name Name
     * @param array{
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'stmts'      => array(): Statements
     *             'attrGroups' => array(): PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'name', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Trait';
    }
}
Node/Stmt/While_.php000064400000001466151520657540010321 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class While_ extends Node\Stmt {
    /** @var Node\Expr Condition */
    public Node\Expr $cond;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a while node.
     *
     * @param Node\Expr $cond Condition
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_While';
    }
}
Node/Stmt/Continue_.php000064400000001311151520657540011022 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Continue_ extends Node\Stmt {
    /** @var null|Node\Expr Number of loops to continue */
    public ?Node\Expr $num;

    /**
     * Constructs a continue node.
     *
     * @param null|Node\Expr $num Number of loops to continue
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Expr $num = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->num = $num;
    }

    public function getSubNodeNames(): array {
        return ['num'];
    }

    public function getType(): string {
        return 'Stmt_Continue';
    }
}
Node/Stmt/UseUse.php000064400000000105151520657540010310 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../UseItem.php';
Node/Stmt/GroupUse.php000064400000002045151520657540010655 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\UseItem;

class GroupUse extends Stmt {
    /**
     * @var Use_::TYPE_* Type of group use
     */
    public int $type;
    /** @var Name Prefix for uses */
    public Name $prefix;
    /** @var UseItem[] Uses */
    public array $uses;

    /**
     * Constructs a group use node.
     *
     * @param Name $prefix Prefix for uses
     * @param UseItem[] $uses Uses
     * @param Use_::TYPE_* $type Type of group use
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Name $prefix, array $uses, int $type = Use_::TYPE_NORMAL, array $attributes = []) {
        $this->attributes = $attributes;
        $this->type = $type;
        $this->prefix = $prefix;
        $this->uses = $uses;
    }

    public function getSubNodeNames(): array {
        return ['type', 'prefix', 'uses'];
    }

    public function getType(): string {
        return 'Stmt_GroupUse';
    }
}
Node/Stmt/TraitUse.php000064400000001571151520657540010647 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class TraitUse extends Node\Stmt {
    /** @var Node\Name[] Traits */
    public array $traits;
    /** @var TraitUseAdaptation[] Adaptations */
    public array $adaptations;

    /**
     * Constructs a trait use node.
     *
     * @param Node\Name[] $traits Traits
     * @param TraitUseAdaptation[] $adaptations Adaptations
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $traits, array $adaptations = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->traits = $traits;
        $this->adaptations = $adaptations;
    }

    public function getSubNodeNames(): array {
        return ['traits', 'adaptations'];
    }

    public function getType(): string {
        return 'Stmt_TraitUse';
    }
}
Node/Stmt/Else_.php000064400000001226151520657540010133 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Else_ extends Node\Stmt {
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs an else node.
     *
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['stmts'];
    }

    public function getType(): string {
        return 'Stmt_Else';
    }
}
Node/Stmt/Enum_.php000064400000003052151520657540010146 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Enum_ extends ClassLike {
    /** @var null|Node\Identifier Scalar Type */
    public ?Node $scalarType;
    /** @var Node\Name[] Names of implemented interfaces */
    public array $implements;

    /**
     * @param string|Node\Identifier|null $name Name
     * @param array{
     *     scalarType?: Node\Identifier|null,
     *     implements?: Node\Name[],
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'scalarType'  => null    : Scalar type
     *             'implements'  => array() : Names of implemented interfaces
     *             'stmts'       => array() : Statements
     *             'attrGroups'  => array() : PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->scalarType = $subNodes['scalarType'] ?? null;
        $this->implements = $subNodes['implements'] ?? [];
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];

        parent::__construct($attributes);
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'name', 'scalarType', 'implements', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Enum';
    }
}
Node/Stmt/Foreach_.php000064400000003256151520657540010617 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Foreach_ extends Node\Stmt {
    /** @var Node\Expr Expression to iterate */
    public Node\Expr $expr;
    /** @var null|Node\Expr Variable to assign key to */
    public ?Node\Expr $keyVar;
    /** @var bool Whether to assign value by reference */
    public bool $byRef;
    /** @var Node\Expr Variable to assign value to */
    public Node\Expr $valueVar;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a foreach node.
     *
     * @param Node\Expr $expr Expression to iterate
     * @param Node\Expr $valueVar Variable to assign value to
     * @param array{
     *     keyVar?: Node\Expr|null,
     *     byRef?: bool,
     *     stmts?: Node\Stmt[],
     * } $subNodes Array of the following optional subnodes:
     *             'keyVar' => null   : Variable to assign key to
     *             'byRef'  => false  : Whether to assign value by reference
     *             'stmts'  => array(): Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $expr, Node\Expr $valueVar, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
        $this->keyVar = $subNodes['keyVar'] ?? null;
        $this->byRef = $subNodes['byRef'] ?? false;
        $this->valueVar = $valueVar;
        $this->stmts = $subNodes['stmts'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Foreach';
    }
}
Node/Stmt/Return_.php000064400000001247151520657540010525 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Return_ extends Node\Stmt {
    /** @var null|Node\Expr Expression */
    public ?Node\Expr $expr;

    /**
     * Constructs a return node.
     *
     * @param null|Node\Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Expr $expr = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Stmt_Return';
    }
}
Node/Stmt/Class_.php000064400000006217151520657540010315 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Modifiers;
use PhpParser\Node;

class Class_ extends ClassLike {
    /** @deprecated Use Modifiers::PUBLIC instead */
    public const MODIFIER_PUBLIC    =  1;
    /** @deprecated Use Modifiers::PROTECTED instead */
    public const MODIFIER_PROTECTED =  2;
    /** @deprecated Use Modifiers::PRIVATE instead */
    public const MODIFIER_PRIVATE   =  4;
    /** @deprecated Use Modifiers::STATIC instead */
    public const MODIFIER_STATIC    =  8;
    /** @deprecated Use Modifiers::ABSTRACT instead */
    public const MODIFIER_ABSTRACT  = 16;
    /** @deprecated Use Modifiers::FINAL instead */
    public const MODIFIER_FINAL     = 32;
    /** @deprecated Use Modifiers::READONLY instead */
    public const MODIFIER_READONLY  = 64;

    /** @deprecated Use Modifiers::VISIBILITY_MASK instead */
    public const VISIBILITY_MODIFIER_MASK = 7; // 1 | 2 | 4

    /** @var int Modifiers */
    public int $flags;
    /** @var null|Node\Name Name of extended class */
    public ?Node\Name $extends;
    /** @var Node\Name[] Names of implemented interfaces */
    public array $implements;

    /**
     * Constructs a class node.
     *
     * @param string|Node\Identifier|null $name Name
     * @param array{
     *     flags?: int,
     *     extends?: Node\Name|null,
     *     implements?: Node\Name[],
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'flags'       => 0      : Flags
     *             'extends'     => null   : Name of extended class
     *             'implements'  => array(): Names of implemented interfaces
     *             'stmts'       => array(): Statements
     *             'attrGroups'  => array(): PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0;
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->extends = $subNodes['extends'] ?? null;
        $this->implements = $subNodes['implements'] ?? [];
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts'];
    }

    /**
     * Whether the class is explicitly abstract.
     */
    public function isAbstract(): bool {
        return (bool) ($this->flags & Modifiers::ABSTRACT);
    }

    /**
     * Whether the class is final.
     */
    public function isFinal(): bool {
        return (bool) ($this->flags & Modifiers::FINAL);
    }

    public function isReadonly(): bool {
        return (bool) ($this->flags & Modifiers::READONLY);
    }

    /**
     * Whether the class is anonymous.
     */
    public function isAnonymous(): bool {
        return null === $this->name;
    }

    public function getType(): string {
        return 'Stmt_Class';
    }
}
Node/Stmt/Break_.php000064400000001272151520657540010270 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Break_ extends Node\Stmt {
    /** @var null|Node\Expr Number of loops to break */
    public ?Node\Expr $num;

    /**
     * Constructs a break node.
     *
     * @param null|Node\Expr $num Number of loops to break
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Expr $num = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->num = $num;
    }

    public function getSubNodeNames(): array {
        return ['num'];
    }

    public function getType(): string {
        return 'Stmt_Break';
    }
}
Node/Stmt/Goto_.php000064400000001365151520657540010157 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;

class Goto_ extends Stmt {
    /** @var Identifier Name of label to jump to */
    public Identifier $name;

    /**
     * Constructs a goto node.
     *
     * @param string|Identifier $name Name of label to jump to
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    public function getType(): string {
        return 'Stmt_Goto';
    }
}
Node/Stmt/ClassConst.php000064400000004124151520657540011160 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Modifiers;
use PhpParser\Node;

class ClassConst extends Node\Stmt {
    /** @var int Modifiers */
    public int $flags;
    /** @var Node\Const_[] Constant declarations */
    public array $consts;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;
    /** @var Node\Identifier|Node\Name|Node\ComplexType|null Type declaration */
    public ?Node $type;

    /**
     * Constructs a class const list node.
     *
     * @param Node\Const_[] $consts Constant declarations
     * @param int $flags Modifiers
     * @param array<string, mixed> $attributes Additional attributes
     * @param list<Node\AttributeGroup> $attrGroups PHP attribute groups
     * @param null|Node\Identifier|Node\Name|Node\ComplexType $type Type declaration
     */
    public function __construct(
        array $consts,
        int $flags = 0,
        array $attributes = [],
        array $attrGroups = [],
        ?Node $type = null
    ) {
        $this->attributes = $attributes;
        $this->flags = $flags;
        $this->consts = $consts;
        $this->attrGroups = $attrGroups;
        $this->type = $type;
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'type', 'consts'];
    }

    /**
     * Whether constant is explicitly or implicitly public.
     */
    public function isPublic(): bool {
        return ($this->flags & Modifiers::PUBLIC) !== 0
            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;
    }

    /**
     * Whether constant is protected.
     */
    public function isProtected(): bool {
        return (bool) ($this->flags & Modifiers::PROTECTED);
    }

    /**
     * Whether constant is private.
     */
    public function isPrivate(): bool {
        return (bool) ($this->flags & Modifiers::PRIVATE);
    }

    /**
     * Whether constant is final.
     */
    public function isFinal(): bool {
        return (bool) ($this->flags & Modifiers::FINAL);
    }

    public function getType(): string {
        return 'Stmt_ClassConst';
    }
}
Node/Stmt/Label.php000064400000001317151520657540010124 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;

class Label extends Stmt {
    /** @var Identifier Name */
    public Identifier $name;

    /**
     * Constructs a label node.
     *
     * @param string|Identifier $name Name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    public function getType(): string {
        return 'Stmt_Label';
    }
}
Node/Stmt/EnumCase.php000064400000002216151520657540010604 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;
use PhpParser\Node\AttributeGroup;

class EnumCase extends Node\Stmt {
    /** @var Node\Identifier Enum case name */
    public Node\Identifier $name;
    /** @var Node\Expr|null Enum case expression */
    public ?Node\Expr $expr;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /**
     * @param string|Node\Identifier $name Enum case name
     * @param Node\Expr|null $expr Enum case expression
     * @param list<AttributeGroup> $attrGroups PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, ?Node\Expr $expr = null, array $attrGroups = [], array $attributes = []) {
        parent::__construct($attributes);
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->expr = $expr;
        $this->attrGroups = $attrGroups;
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'name', 'expr'];
    }

    public function getType(): string {
        return 'Stmt_EnumCase';
    }
}
Node/Stmt/Catch_.php000064400000002132151520657540010262 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;
use PhpParser\Node\Expr;

class Catch_ extends Node\Stmt {
    /** @var Node\Name[] Types of exceptions to catch */
    public array $types;
    /** @var Expr\Variable|null Variable for exception */
    public ?Expr\Variable $var;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a catch node.
     *
     * @param Node\Name[] $types Types of exceptions to catch
     * @param Expr\Variable|null $var Variable for exception
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(
        array $types, ?Expr\Variable $var = null, array $stmts = [], array $attributes = []
    ) {
        $this->attributes = $attributes;
        $this->types = $types;
        $this->var = $var;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['types', 'var', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Catch';
    }
}
Node/Stmt/If_.php000064400000002560151520657540007603 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class If_ extends Node\Stmt {
    /** @var Node\Expr Condition expression */
    public Node\Expr $cond;
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var ElseIf_[] Elseif clauses */
    public array $elseifs;
    /** @var null|Else_ Else clause */
    public ?Else_ $else;

    /**
     * Constructs an if node.
     *
     * @param Node\Expr $cond Condition
     * @param array{
     *     stmts?: Node\Stmt[],
     *     elseifs?: ElseIf_[],
     *     else?: Else_|null,
     * } $subNodes Array of the following optional subnodes:
     *             'stmts'   => array(): Statements
     *             'elseifs' => array(): Elseif clauses
     *             'else'    => null   : Else clause
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->elseifs = $subNodes['elseifs'] ?? [];
        $this->else = $subNodes['else'] ?? null;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'stmts', 'elseifs', 'else'];
    }

    public function getType(): string {
        return 'Stmt_If';
    }
}
Node/Stmt/HaltCompiler.php000064400000001400151520657540011461 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Stmt;

class HaltCompiler extends Stmt {
    /** @var string Remaining text after halt compiler statement. */
    public string $remaining;

    /**
     * Constructs a __halt_compiler node.
     *
     * @param string $remaining Remaining text after halt compiler statement.
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(string $remaining, array $attributes = []) {
        $this->attributes = $attributes;
        $this->remaining = $remaining;
    }

    public function getSubNodeNames(): array {
        return ['remaining'];
    }

    public function getType(): string {
        return 'Stmt_HaltCompiler';
    }
}
Node/Stmt/InlineHTML.php000064400000001223151520657540011004 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Stmt;

class InlineHTML extends Stmt {
    /** @var string String */
    public string $value;

    /**
     * Constructs an inline HTML node.
     *
     * @param string $value String
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(string $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['value'];
    }

    public function getType(): string {
        return 'Stmt_InlineHTML';
    }
}
Node/Stmt/DeclareDeclare.php000064400000000111151520657540011713 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../DeclareItem.php';
Node/Stmt/Echo_.php000064400000001223151520657540010116 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Echo_ extends Node\Stmt {
    /** @var Node\Expr[] Expressions */
    public array $exprs;

    /**
     * Constructs an echo node.
     *
     * @param Node\Expr[] $exprs Expressions
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $exprs, array $attributes = []) {
        $this->attributes = $attributes;
        $this->exprs = $exprs;
    }

    public function getSubNodeNames(): array {
        return ['exprs'];
    }

    public function getType(): string {
        return 'Stmt_Echo';
    }
}
Node/Stmt/Expression.php000064400000001326151520657540011244 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

/**
 * Represents statements of type "expr;"
 */
class Expression extends Node\Stmt {
    /** @var Node\Expr Expression */
    public Node\Expr $expr;

    /**
     * Constructs an expression statement.
     *
     * @param Node\Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Stmt_Expression';
    }
}
Node/Stmt/Switch_.php000064400000001450151520657540010503 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Switch_ extends Node\Stmt {
    /** @var Node\Expr Condition */
    public Node\Expr $cond;
    /** @var Case_[] Case list */
    public array $cases;

    /**
     * Constructs a case node.
     *
     * @param Node\Expr $cond Condition
     * @param Case_[] $cases Case list
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $cases, array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->cases = $cases;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'cases'];
    }

    public function getType(): string {
        return 'Stmt_Switch';
    }
}
Node/Stmt/ElseIf_.php000064400000001472151520657540010415 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class ElseIf_ extends Node\Stmt {
    /** @var Node\Expr Condition */
    public Node\Expr $cond;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs an elseif node.
     *
     * @param Node\Expr $cond Condition
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_ElseIf';
    }
}
Node/Stmt/Finally_.php000064400000001236151520657540010642 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Finally_ extends Node\Stmt {
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a finally node.
     *
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['stmts'];
    }

    public function getType(): string {
        return 'Stmt_Finally';
    }
}
Node/Stmt/Global_.php000064400000001246151520657540010445 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Global_ extends Node\Stmt {
    /** @var Node\Expr[] Variables */
    public array $vars;

    /**
     * Constructs a global variables list node.
     *
     * @param Node\Expr[] $vars Variables to unset
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $vars, array $attributes = []) {
        $this->attributes = $attributes;
        $this->vars = $vars;
    }

    public function getSubNodeNames(): array {
        return ['vars'];
    }

    public function getType(): string {
        return 'Stmt_Global';
    }
}
Node/Stmt/Nop.php000064400000000447151520657540007644 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

/** Nop/empty statement (;). */
class Nop extends Node\Stmt {
    public function getSubNodeNames(): array {
        return [];
    }

    public function getType(): string {
        return 'Stmt_Nop';
    }
}
Node/Stmt/Function_.php000064400000005160151520657540011031 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;
use PhpParser\Node\FunctionLike;

class Function_ extends Node\Stmt implements FunctionLike {
    /** @var bool Whether function returns by reference */
    public bool $byRef;
    /** @var Node\Identifier Name */
    public Node\Identifier $name;
    /** @var Node\Param[] Parameters */
    public array $params;
    /** @var null|Node\Identifier|Node\Name|Node\ComplexType Return type */
    public ?Node $returnType;
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /** @var Node\Name|null Namespaced name (if using NameResolver) */
    public ?Node\Name $namespacedName;

    /**
     * Constructs a function node.
     *
     * @param string|Node\Identifier $name Name
     * @param array{
     *     byRef?: bool,
     *     params?: Node\Param[],
     *     returnType?: null|Node\Identifier|Node\Name|Node\ComplexType,
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'byRef'      => false  : Whether to return by reference
     *             'params'     => array(): Parameters
     *             'returnType' => null   : Return type
     *             'stmts'      => array(): Statements
     *             'attrGroups' => array(): PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->byRef = $subNodes['byRef'] ?? false;
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->params = $subNodes['params'] ?? [];
        $this->returnType = $subNodes['returnType'] ?? null;
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts'];
    }

    public function returnsByRef(): bool {
        return $this->byRef;
    }

    public function getParams(): array {
        return $this->params;
    }

    public function getReturnType() {
        return $this->returnType;
    }

    public function getAttrGroups(): array {
        return $this->attrGroups;
    }

    /** @return Node\Stmt[] */
    public function getStmts(): array {
        return $this->stmts;
    }

    public function getType(): string {
        return 'Stmt_Function';
    }
}
Node/Stmt/ClassMethod.php000064400000011154151520657540011313 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\FunctionLike;

class ClassMethod extends Node\Stmt implements FunctionLike {
    /** @var int Flags */
    public int $flags;
    /** @var bool Whether to return by reference */
    public bool $byRef;
    /** @var Node\Identifier Name */
    public Node\Identifier $name;
    /** @var Node\Param[] Parameters */
    public array $params;
    /** @var null|Node\Identifier|Node\Name|Node\ComplexType Return type */
    public ?Node $returnType;
    /** @var Node\Stmt[]|null Statements */
    public ?array $stmts;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /** @var array<string, bool> */
    private static array $magicNames = [
        '__construct'   => true,
        '__destruct'    => true,
        '__call'        => true,
        '__callstatic'  => true,
        '__get'         => true,
        '__set'         => true,
        '__isset'       => true,
        '__unset'       => true,
        '__sleep'       => true,
        '__wakeup'      => true,
        '__tostring'    => true,
        '__set_state'   => true,
        '__clone'       => true,
        '__invoke'      => true,
        '__debuginfo'   => true,
        '__serialize'   => true,
        '__unserialize' => true,
    ];

    /**
     * Constructs a class method node.
     *
     * @param string|Node\Identifier $name Name
     * @param array{
     *     flags?: int,
     *     byRef?: bool,
     *     params?: Node\Param[],
     *     returnType?: null|Node\Identifier|Node\Name|Node\ComplexType,
     *     stmts?: Node\Stmt[]|null,
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'flags       => 0              : Flags
     *             'byRef'      => false          : Whether to return by reference
     *             'params'     => array()        : Parameters
     *             'returnType' => null           : Return type
     *             'stmts'      => array()        : Statements
     *             'attrGroups' => array()        : PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0;
        $this->byRef = $subNodes['byRef'] ?? false;
        $this->name = \is_string($name) ? new Node\Identifier($name) : $name;
        $this->params = $subNodes['params'] ?? [];
        $this->returnType = $subNodes['returnType'] ?? null;
        $this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts'];
    }

    public function returnsByRef(): bool {
        return $this->byRef;
    }

    public function getParams(): array {
        return $this->params;
    }

    public function getReturnType() {
        return $this->returnType;
    }

    public function getStmts(): ?array {
        return $this->stmts;
    }

    public function getAttrGroups(): array {
        return $this->attrGroups;
    }

    /**
     * Whether the method is explicitly or implicitly public.
     */
    public function isPublic(): bool {
        return ($this->flags & Modifiers::PUBLIC) !== 0
            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;
    }

    /**
     * Whether the method is protected.
     */
    public function isProtected(): bool {
        return (bool) ($this->flags & Modifiers::PROTECTED);
    }

    /**
     * Whether the method is private.
     */
    public function isPrivate(): bool {
        return (bool) ($this->flags & Modifiers::PRIVATE);
    }

    /**
     * Whether the method is abstract.
     */
    public function isAbstract(): bool {
        return (bool) ($this->flags & Modifiers::ABSTRACT);
    }

    /**
     * Whether the method is final.
     */
    public function isFinal(): bool {
        return (bool) ($this->flags & Modifiers::FINAL);
    }

    /**
     * Whether the method is static.
     */
    public function isStatic(): bool {
        return (bool) ($this->flags & Modifiers::STATIC);
    }

    /**
     * Whether the method is magic.
     */
    public function isMagic(): bool {
        return isset(self::$magicNames[$this->name->toLowerString()]);
    }

    public function getType(): string {
        return 'Stmt_ClassMethod';
    }
}
Node/Stmt/ClassLike.php000064400000005724151520657540010765 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;
use PhpParser\Node\PropertyItem;

abstract class ClassLike extends Node\Stmt {
    /** @var Node\Identifier|null Name */
    public ?Node\Identifier $name;
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /** @var Node\Name|null Namespaced name (if using NameResolver) */
    public ?Node\Name $namespacedName;

    /**
     * @return TraitUse[]
     */
    public function getTraitUses(): array {
        $traitUses = [];
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof TraitUse) {
                $traitUses[] = $stmt;
            }
        }
        return $traitUses;
    }

    /**
     * @return ClassConst[]
     */
    public function getConstants(): array {
        $constants = [];
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof ClassConst) {
                $constants[] = $stmt;
            }
        }
        return $constants;
    }

    /**
     * @return Property[]
     */
    public function getProperties(): array {
        $properties = [];
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof Property) {
                $properties[] = $stmt;
            }
        }
        return $properties;
    }

    /**
     * Gets property with the given name defined directly in this class/interface/trait.
     *
     * @param string $name Name of the property
     *
     * @return Property|null Property node or null if the property does not exist
     */
    public function getProperty(string $name): ?Property {
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof Property) {
                foreach ($stmt->props as $prop) {
                    if ($prop instanceof PropertyItem && $name === $prop->name->toString()) {
                        return $stmt;
                    }
                }
            }
        }
        return null;
    }

    /**
     * Gets all methods defined directly in this class/interface/trait
     *
     * @return ClassMethod[]
     */
    public function getMethods(): array {
        $methods = [];
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof ClassMethod) {
                $methods[] = $stmt;
            }
        }
        return $methods;
    }

    /**
     * Gets method with the given name defined directly in this class/interface/trait.
     *
     * @param string $name Name of the method (compared case-insensitively)
     *
     * @return ClassMethod|null Method node or null if the method does not exist
     */
    public function getMethod(string $name): ?ClassMethod {
        $lowerName = strtolower($name);
        foreach ($this->stmts as $stmt) {
            if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) {
                return $stmt;
            }
        }
        return null;
    }
}
Node/Stmt/Case_.php000064400000001545151520657540010122 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Case_ extends Node\Stmt {
    /** @var null|Node\Expr Condition (null for default) */
    public ?Node\Expr $cond;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a case node.
     *
     * @param null|Node\Expr $cond Condition (null for default)
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Expr $cond, array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Case';
    }
}
Node/Stmt/Declare_.php000064400000001620151520657540010600 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;
use PhpParser\Node\DeclareItem;

class Declare_ extends Node\Stmt {
    /** @var DeclareItem[] List of declares */
    public array $declares;
    /** @var Node\Stmt[]|null Statements */
    public ?array $stmts;

    /**
     * Constructs a declare node.
     *
     * @param DeclareItem[] $declares List of declares
     * @param Node\Stmt[]|null $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $declares, ?array $stmts = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->declares = $declares;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['declares', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Declare';
    }
}
Node/Stmt/Do_.php000064400000001463151520657540007610 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Do_ extends Node\Stmt {
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var Node\Expr Condition */
    public Node\Expr $cond;

    /**
     * Constructs a do while node.
     *
     * @param Node\Expr $cond Condition
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['stmts', 'cond'];
    }

    public function getType(): string {
        return 'Stmt_Do';
    }
}
Node/Stmt/Static_.php000064400000001321151520657540010466 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\StaticVar;
use PhpParser\Node\Stmt;

class Static_ extends Stmt {
    /** @var StaticVar[] Variable definitions */
    public array $vars;

    /**
     * Constructs a static variables list node.
     *
     * @param StaticVar[] $vars Variable definitions
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $vars, array $attributes = []) {
        $this->attributes = $attributes;
        $this->vars = $vars;
    }

    public function getSubNodeNames(): array {
        return ['vars'];
    }

    public function getType(): string {
        return 'Stmt_Static';
    }
}
Node/Stmt/TraitUseAdaptation/Alias.php000064400000002420151520657540013677 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt\TraitUseAdaptation;

use PhpParser\Node;

class Alias extends Node\Stmt\TraitUseAdaptation {
    /** @var null|int New modifier */
    public ?int $newModifier;
    /** @var null|Node\Identifier New name */
    public ?Node\Identifier $newName;

    /**
     * Constructs a trait use precedence adaptation node.
     *
     * @param null|Node\Name $trait Trait name
     * @param string|Node\Identifier $method Method name
     * @param null|int $newModifier New modifier
     * @param null|string|Node\Identifier $newName New name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Name $trait, $method, ?int $newModifier, $newName, array $attributes = []) {
        $this->attributes = $attributes;
        $this->trait = $trait;
        $this->method = \is_string($method) ? new Node\Identifier($method) : $method;
        $this->newModifier = $newModifier;
        $this->newName = \is_string($newName) ? new Node\Identifier($newName) : $newName;
    }

    public function getSubNodeNames(): array {
        return ['trait', 'method', 'newModifier', 'newName'];
    }

    public function getType(): string {
        return 'Stmt_TraitUseAdaptation_Alias';
    }
}
Node/Stmt/TraitUseAdaptation/Precedence.php000064400000002035151520657540014705 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt\TraitUseAdaptation;

use PhpParser\Node;

class Precedence extends Node\Stmt\TraitUseAdaptation {
    /** @var Node\Name[] Overwritten traits */
    public array $insteadof;

    /**
     * Constructs a trait use precedence adaptation node.
     *
     * @param Node\Name $trait Trait name
     * @param string|Node\Identifier $method Method name
     * @param Node\Name[] $insteadof Overwritten traits
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Name $trait, $method, array $insteadof, array $attributes = []) {
        $this->attributes = $attributes;
        $this->trait = $trait;
        $this->method = \is_string($method) ? new Node\Identifier($method) : $method;
        $this->insteadof = $insteadof;
    }

    public function getSubNodeNames(): array {
        return ['trait', 'method', 'insteadof'];
    }

    public function getType(): string {
        return 'Stmt_TraitUseAdaptation_Precedence';
    }
}
Node/Stmt/Namespace_.php000064400000001675151520657540011147 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class Namespace_ extends Node\Stmt {
    /* For use in the "kind" attribute */
    public const KIND_SEMICOLON = 1;
    public const KIND_BRACED = 2;

    /** @var null|Node\Name Name */
    public ?Node\Name $name;
    /** @var Node\Stmt[] Statements */
    public $stmts;

    /**
     * Constructs a namespace node.
     *
     * @param null|Node\Name $name Name
     * @param null|Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Node\Name $name = null, ?array $stmts = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
        $this->stmts = $stmts;
    }

    public function getSubNodeNames(): array {
        return ['name', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_Namespace';
    }
}
Node/Stmt/PropertyProperty.php000064400000000112151520657540012466 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../PropertyItem.php';
Node/Stmt/TryCatch.php000064400000002025151520657540010623 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class TryCatch extends Node\Stmt {
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var Catch_[] Catches */
    public array $catches;
    /** @var null|Finally_ Optional finally node */
    public ?Finally_ $finally;

    /**
     * Constructs a try catch node.
     *
     * @param Node\Stmt[] $stmts Statements
     * @param Catch_[] $catches Catches
     * @param null|Finally_ $finally Optional finally node
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->stmts = $stmts;
        $this->catches = $catches;
        $this->finally = $finally;
    }

    public function getSubNodeNames(): array {
        return ['stmts', 'catches', 'finally'];
    }

    public function getType(): string {
        return 'Stmt_TryCatch';
    }
}
Node/Stmt/Use_.php000064400000002650151520657540010001 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node\Stmt;
use PhpParser\Node\UseItem;

class Use_ extends Stmt {
    /**
     * Unknown type. Both Stmt\Use_ / Stmt\GroupUse and Stmt\UseUse have a $type property, one of them will always be
     * TYPE_UNKNOWN while the other has one of the three other possible types. For normal use statements the type on the
     * Stmt\UseUse is unknown. It's only the other way around for mixed group use declarations.
     */
    public const TYPE_UNKNOWN = 0;
    /** Class or namespace import */
    public const TYPE_NORMAL = 1;
    /** Function import */
    public const TYPE_FUNCTION = 2;
    /** Constant import */
    public const TYPE_CONSTANT = 3;

    /** @var self::TYPE_* Type of alias */
    public int $type;
    /** @var UseItem[] Aliases */
    public array $uses;

    /**
     * Constructs an alias (use) list node.
     *
     * @param UseItem[] $uses Aliases
     * @param Stmt\Use_::TYPE_* $type Type of alias
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $uses, int $type = self::TYPE_NORMAL, array $attributes = []) {
        $this->attributes = $attributes;
        $this->type = $type;
        $this->uses = $uses;
    }

    public function getSubNodeNames(): array {
        return ['type', 'uses'];
    }

    public function getType(): string {
        return 'Stmt_Use';
    }
}
Node/Stmt/For_.php000064400000002633151520657540007774 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Stmt;

use PhpParser\Node;

class For_ extends Node\Stmt {
    /** @var Node\Expr[] Init expressions */
    public array $init;
    /** @var Node\Expr[] Loop conditions */
    public array $cond;
    /** @var Node\Expr[] Loop expressions */
    public array $loop;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * Constructs a for loop node.
     *
     * @param array{
     *     init?: Node\Expr[],
     *     cond?: Node\Expr[],
     *     loop?: Node\Expr[],
     *     stmts?: Node\Stmt[],
     * } $subNodes Array of the following optional subnodes:
     *             'init'  => array(): Init expressions
     *             'cond'  => array(): Loop conditions
     *             'loop'  => array(): Loop expressions
     *             'stmts' => array(): Statements
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->init = $subNodes['init'] ?? [];
        $this->cond = $subNodes['cond'] ?? [];
        $this->loop = $subNodes['loop'] ?? [];
        $this->stmts = $subNodes['stmts'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['init', 'cond', 'loop', 'stmts'];
    }

    public function getType(): string {
        return 'Stmt_For';
    }
}
Node/IntersectionType.php000064400000001231151520657540011461 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

class IntersectionType extends ComplexType {
    /** @var (Identifier|Name)[] Types */
    public array $types;

    /**
     * Constructs an intersection type.
     *
     * @param (Identifier|Name)[] $types Types
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $types, array $attributes = []) {
        $this->attributes = $attributes;
        $this->types = $types;
    }

    public function getSubNodeNames(): array {
        return ['types'];
    }

    public function getType(): string {
        return 'IntersectionType';
    }
}
Node/Stmt.php000064400000000205151520657540007100 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

abstract class Stmt extends NodeAbstract {
}
Node/Scalar/Float_.php000064400000004065151520657540010572 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar;

use PhpParser\Node\Scalar;

class Float_ extends Scalar {
    /** @var float Number value */
    public float $value;

    /**
     * Constructs a float number scalar node.
     *
     * @param float $value Value of the number
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(float $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['value'];
    }

    /**
     * @param mixed[] $attributes
     */
    public static function fromString(string $str, array $attributes = []): Float_ {
        $attributes['rawValue'] = $str;
        $float = self::parse($str);

        return new Float_($float, $attributes);
    }

    /**
     * @internal
     *
     * Parses a DNUMBER token like PHP would.
     *
     * @param string $str A string number
     *
     * @return float The parsed number
     */
    public static function parse(string $str): float {
        $str = str_replace('_', '', $str);

        // Check whether this is one of the special integer notations.
        if ('0' === $str[0]) {
            // hex
            if ('x' === $str[1] || 'X' === $str[1]) {
                return hexdec($str);
            }

            // bin
            if ('b' === $str[1] || 'B' === $str[1]) {
                return bindec($str);
            }

            // oct, but only if the string does not contain any of '.eE'.
            if (false === strpbrk($str, '.eE')) {
                // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit
                // (8 or 9) so that only the digits before that are used.
                return octdec(substr($str, 0, strcspn($str, '89')));
            }
        }

        // dec
        return (float) $str;
    }

    public function getType(): string {
        return 'Scalar_Float';
    }
}

// @deprecated compatibility alias
class_alias(Float_::class, DNumber::class);
Node/Scalar/MagicConst.php000064400000001132151520657540011405 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar;

use PhpParser\Node\Scalar;

abstract class MagicConst extends Scalar {
    /**
     * Constructs a magic constant node.
     *
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $attributes = []) {
        $this->attributes = $attributes;
    }

    public function getSubNodeNames(): array {
        return [];
    }

    /**
     * Get name of magic constant.
     *
     * @return string Name of magic constant
     */
    abstract public function getName(): string;
}
Node/Scalar/DNumber.php000064400000000101151520657540010705 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/Float_.php';
Node/Scalar/Encapsed.php000064400000000115151520657540011100 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/InterpolatedString.php';
Node/Scalar/String_.php000064400000011717151520657540010775 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar;

use PhpParser\Error;
use PhpParser\Node\Scalar;

class String_ extends Scalar {
    /* For use in "kind" attribute */
    public const KIND_SINGLE_QUOTED = 1;
    public const KIND_DOUBLE_QUOTED = 2;
    public const KIND_HEREDOC = 3;
    public const KIND_NOWDOC = 4;

    /** @var string String value */
    public string $value;

    /** @var array<string, string> Escaped character to its decoded value */
    protected static array $replacements = [
        '\\' => '\\',
        '$'  =>  '$',
        'n'  => "\n",
        'r'  => "\r",
        't'  => "\t",
        'f'  => "\f",
        'v'  => "\v",
        'e'  => "\x1B",
    ];

    /**
     * Constructs a string scalar node.
     *
     * @param string $value Value of the string
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(string $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['value'];
    }

    /**
     * @param array<string, mixed> $attributes
     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
     */
    public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = true): self {
        $attributes['kind'] = ($str[0] === "'" || ($str[1] === "'" && ($str[0] === 'b' || $str[0] === 'B')))
            ? Scalar\String_::KIND_SINGLE_QUOTED
            : Scalar\String_::KIND_DOUBLE_QUOTED;

        $attributes['rawValue'] = $str;

        $string = self::parse($str, $parseUnicodeEscape);

        return new self($string, $attributes);
    }

    /**
     * @internal
     *
     * Parses a string token.
     *
     * @param string $str String token content
     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
     *
     * @return string The parsed string
     */
    public static function parse(string $str, bool $parseUnicodeEscape = true): string {
        $bLength = 0;
        if ('b' === $str[0] || 'B' === $str[0]) {
            $bLength = 1;
        }

        if ('\'' === $str[$bLength]) {
            return str_replace(
                ['\\\\', '\\\''],
                ['\\', '\''],
                substr($str, $bLength + 1, -1)
            );
        } else {
            return self::parseEscapeSequences(
                substr($str, $bLength + 1, -1), '"', $parseUnicodeEscape
            );
        }
    }

    /**
     * @internal
     *
     * Parses escape sequences in strings (all string types apart from single quoted).
     *
     * @param string $str String without quotes
     * @param null|string $quote Quote type
     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \u escapes
     *
     * @return string String with escape sequences parsed
     */
    public static function parseEscapeSequences(string $str, ?string $quote, bool $parseUnicodeEscape = true): string {
        if (null !== $quote) {
            $str = str_replace('\\' . $quote, $quote, $str);
        }

        $extra = '';
        if ($parseUnicodeEscape) {
            $extra = '|u\{([0-9a-fA-F]+)\}';
        }

        return preg_replace_callback(
            '~\\\\([\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~',
            function ($matches) {
                $str = $matches[1];

                if (isset(self::$replacements[$str])) {
                    return self::$replacements[$str];
                }
                if ('x' === $str[0] || 'X' === $str[0]) {
                    return chr(hexdec(substr($str, 1)));
                }
                if ('u' === $str[0]) {
                    $dec = hexdec($matches[2]);
                    // If it overflowed to float, treat as INT_MAX, it will throw an error anyway.
                    return self::codePointToUtf8(\is_int($dec) ? $dec : \PHP_INT_MAX);
                } else {
                    return chr(octdec($str));
                }
            },
            $str
        );
    }

    /**
     * Converts a Unicode code point to its UTF-8 encoded representation.
     *
     * @param int $num Code point
     *
     * @return string UTF-8 representation of code point
     */
    private static function codePointToUtf8(int $num): string {
        if ($num <= 0x7F) {
            return chr($num);
        }
        if ($num <= 0x7FF) {
            return chr(($num >> 6) + 0xC0) . chr(($num & 0x3F) + 0x80);
        }
        if ($num <= 0xFFFF) {
            return chr(($num >> 12) + 0xE0) . chr((($num >> 6) & 0x3F) + 0x80) . chr(($num & 0x3F) + 0x80);
        }
        if ($num <= 0x1FFFFF) {
            return chr(($num >> 18) + 0xF0) . chr((($num >> 12) & 0x3F) + 0x80)
                 . chr((($num >> 6) & 0x3F) + 0x80) . chr(($num & 0x3F) + 0x80);
        }
        throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large');
    }

    public function getType(): string {
        return 'Scalar_String';
    }
}
Node/Scalar/EncapsedStringPart.php000064400000000124151520657540013116 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../InterpolatedStringPart.php';
Node/Scalar/InterpolatedString.php000064400000001645151520657540013210 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar;

use PhpParser\Node\Expr;
use PhpParser\Node\InterpolatedStringPart;
use PhpParser\Node\Scalar;

class InterpolatedString extends Scalar {
    /** @var (Expr|InterpolatedStringPart)[] list of string parts */
    public array $parts;

    /**
     * Constructs an interpolated string node.
     *
     * @param (Expr|InterpolatedStringPart)[] $parts Interpolated string parts
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $parts, array $attributes = []) {
        $this->attributes = $attributes;
        $this->parts = $parts;
    }

    public function getSubNodeNames(): array {
        return ['parts'];
    }

    public function getType(): string {
        return 'Scalar_InterpolatedString';
    }
}

// @deprecated compatibility alias
class_alias(InterpolatedString::class, Encapsed::class);
Node/Scalar/Int_.php000064400000004720151520657540010255 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar;

use PhpParser\Error;
use PhpParser\Node\Scalar;

class Int_ extends Scalar {
    /* For use in "kind" attribute */
    public const KIND_BIN = 2;
    public const KIND_OCT = 8;
    public const KIND_DEC = 10;
    public const KIND_HEX = 16;

    /** @var int Number value */
    public int $value;

    /**
     * Constructs an integer number scalar node.
     *
     * @param int $value Value of the number
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(int $value, array $attributes = []) {
        $this->attributes = $attributes;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['value'];
    }

    /**
     * Constructs an Int node from a string number literal.
     *
     * @param string $str String number literal (decimal, octal, hex or binary)
     * @param array<string, mixed> $attributes Additional attributes
     * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5)
     *
     * @return Int_ The constructed LNumber, including kind attribute
     */
    public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = false): Int_ {
        $attributes['rawValue'] = $str;

        $str = str_replace('_', '', $str);

        if ('0' !== $str[0] || '0' === $str) {
            $attributes['kind'] = Int_::KIND_DEC;
            return new Int_((int) $str, $attributes);
        }

        if ('x' === $str[1] || 'X' === $str[1]) {
            $attributes['kind'] = Int_::KIND_HEX;
            return new Int_(hexdec($str), $attributes);
        }

        if ('b' === $str[1] || 'B' === $str[1]) {
            $attributes['kind'] = Int_::KIND_BIN;
            return new Int_(bindec($str), $attributes);
        }

        if (!$allowInvalidOctal && strpbrk($str, '89')) {
            throw new Error('Invalid numeric literal', $attributes);
        }

        // Strip optional explicit octal prefix.
        if ('o' === $str[1] || 'O' === $str[1]) {
            $str = substr($str, 2);
        }

        // use intval instead of octdec to get proper cutting behavior with malformed numbers
        $attributes['kind'] = Int_::KIND_OCT;
        return new Int_(intval($str, 8), $attributes);
    }

    public function getType(): string {
        return 'Scalar_Int';
    }
}

// @deprecated compatibility alias
class_alias(Int_::class, LNumber::class);
Node/Scalar/MagicConst/Trait_.php000064400000000473151520657540012636 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Trait_ extends MagicConst {
    public function getName(): string {
        return '__TRAIT__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Trait';
    }
}
Node/Scalar/MagicConst/Class_.php000064400000000473151520657540012620 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Class_ extends MagicConst {
    public function getName(): string {
        return '__CLASS__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Class';
    }
}
Node/Scalar/MagicConst/Line.php000064400000000467151520657540012306 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Line extends MagicConst {
    public function getName(): string {
        return '__LINE__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Line';
    }
}
Node/Scalar/MagicConst/File.php000064400000000467151520657540012276 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class File extends MagicConst {
    public function getName(): string {
        return '__FILE__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_File';
    }
}
Node/Scalar/MagicConst/Function_.php000064400000000504151520657540013333 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Function_ extends MagicConst {
    public function getName(): string {
        return '__FUNCTION__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Function';
    }
}
Node/Scalar/MagicConst/Dir.php000064400000000464151520657540012132 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Dir extends MagicConst {
    public function getName(): string {
        return '__DIR__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Dir';
    }
}
Node/Scalar/MagicConst/Namespace_.php000064400000000507151520657540013445 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Namespace_ extends MagicConst {
    public function getName(): string {
        return '__NAMESPACE__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Namespace';
    }
}
Node/Scalar/MagicConst/Method.php000064400000000475151520657540012636 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Scalar\MagicConst;

use PhpParser\Node\Scalar\MagicConst;

class Method extends MagicConst {
    public function getName(): string {
        return '__METHOD__';
    }

    public function getType(): string {
        return 'Scalar_MagicConst_Method';
    }
}
Node/Scalar/LNumber.php000064400000000077151520657540010731 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/Int_.php';
Node/Param.php000064400000005061151520657540007216 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\NodeAbstract;

class Param extends NodeAbstract {
    /** @var null|Identifier|Name|ComplexType Type declaration */
    public ?Node $type;
    /** @var bool Whether parameter is passed by reference */
    public bool $byRef;
    /** @var bool Whether this is a variadic argument */
    public bool $variadic;
    /** @var Expr\Variable|Expr\Error Parameter variable */
    public Expr $var;
    /** @var null|Expr Default value */
    public ?Expr $default;
    /** @var int Optional visibility flags */
    public int $flags;
    /** @var AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /**
     * Constructs a parameter node.
     *
     * @param Expr\Variable|Expr\Error $var Parameter variable
     * @param null|Expr $default Default value
     * @param null|Identifier|Name|ComplexType $type Type declaration
     * @param bool $byRef Whether is passed by reference
     * @param bool $variadic Whether this is a variadic argument
     * @param array<string, mixed> $attributes Additional attributes
     * @param int $flags Optional visibility flags
     * @param list<AttributeGroup> $attrGroups PHP attribute groups
     */
    public function __construct(
        Expr $var, ?Expr $default = null, ?Node $type = null,
        bool $byRef = false, bool $variadic = false,
        array $attributes = [],
        int $flags = 0,
        array $attrGroups = []
    ) {
        $this->attributes = $attributes;
        $this->type = $type;
        $this->byRef = $byRef;
        $this->variadic = $variadic;
        $this->var = $var;
        $this->default = $default;
        $this->flags = $flags;
        $this->attrGroups = $attrGroups;
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default'];
    }

    public function getType(): string {
        return 'Param';
    }

    /**
     * Whether this parameter uses constructor property promotion.
     */
    public function isPromoted(): bool {
        return $this->flags !== 0;
    }

    public function isPublic(): bool {
        return (bool) ($this->flags & Modifiers::PUBLIC);
    }

    public function isProtected(): bool {
        return (bool) ($this->flags & Modifiers::PROTECTED);
    }

    public function isPrivate(): bool {
        return (bool) ($this->flags & Modifiers::PRIVATE);
    }

    public function isReadonly(): bool {
        return (bool) ($this->flags & Modifiers::READONLY);
    }
}
Node/PropertyItem.php000064400000002060151520657540010615 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;

class PropertyItem extends NodeAbstract {
    /** @var Node\VarLikeIdentifier Name */
    public VarLikeIdentifier $name;
    /** @var null|Node\Expr Default */
    public ?Expr $default;

    /**
     * Constructs a class property item node.
     *
     * @param string|Node\VarLikeIdentifier $name Name
     * @param null|Node\Expr $default Default value
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, ?Node\Expr $default = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = \is_string($name) ? new Node\VarLikeIdentifier($name) : $name;
        $this->default = $default;
    }

    public function getSubNodeNames(): array {
        return ['name', 'default'];
    }

    public function getType(): string {
        return 'PropertyItem';
    }
}

// @deprecated compatibility alias
class_alias(PropertyItem::class, Stmt\PropertyProperty::class);
Node/Name.php000064400000020265151520657540007041 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class Name extends NodeAbstract {
    /** @var string Name as string */
    public string $name;

    /** @var array<string, bool> */
    private static array $specialClassNames = [
        'self'   => true,
        'parent' => true,
        'static' => true,
    ];

    /**
     * Constructs a name node.
     *
     * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor)
     * @param array<string, mixed> $attributes Additional attributes
     */
    final public function __construct($name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = self::prepareName($name);
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    /**
     * Get parts of name (split by the namespace separator).
     *
     * @return string[] Parts of name
     */
    public function getParts(): array {
        return \explode('\\', $this->name);
    }

    /**
     * Gets the first part of the name, i.e. everything before the first namespace separator.
     *
     * @return string First part of the name
     */
    public function getFirst(): string {
        if (false !== $pos = \strpos($this->name, '\\')) {
            return \substr($this->name, 0, $pos);
        }
        return $this->name;
    }

    /**
     * Gets the last part of the name, i.e. everything after the last namespace separator.
     *
     * @return string Last part of the name
     */
    public function getLast(): string {
        if (false !== $pos = \strrpos($this->name, '\\')) {
            return \substr($this->name, $pos + 1);
        }
        return $this->name;
    }

    /**
     * Checks whether the name is unqualified. (E.g. Name)
     *
     * @return bool Whether the name is unqualified
     */
    public function isUnqualified(): bool {
        return false === \strpos($this->name, '\\');
    }

    /**
     * Checks whether the name is qualified. (E.g. Name\Name)
     *
     * @return bool Whether the name is qualified
     */
    public function isQualified(): bool {
        return false !== \strpos($this->name, '\\');
    }

    /**
     * Checks whether the name is fully qualified. (E.g. \Name)
     *
     * @return bool Whether the name is fully qualified
     */
    public function isFullyQualified(): bool {
        return false;
    }

    /**
     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\Name)
     *
     * @return bool Whether the name is relative
     */
    public function isRelative(): bool {
        return false;
    }

    /**
     * Returns a string representation of the name itself, without taking the name type into
     * account (e.g., not including a leading backslash for fully qualified names).
     *
     * @return string String representation
     */
    public function toString(): string {
        return $this->name;
    }

    /**
     * Returns a string representation of the name as it would occur in code (e.g., including
     * leading backslash for fully qualified names.
     *
     * @return string String representation
     */
    public function toCodeString(): string {
        return $this->toString();
    }

    /**
     * Returns lowercased string representation of the name, without taking the name type into
     * account (e.g., no leading backslash for fully qualified names).
     *
     * @return string Lowercased string representation
     */
    public function toLowerString(): string {
        return strtolower($this->name);
    }

    /**
     * Checks whether the identifier is a special class name (self, parent or static).
     *
     * @return bool Whether identifier is a special class name
     */
    public function isSpecialClassName(): bool {
        return isset(self::$specialClassNames[strtolower($this->name)]);
    }

    /**
     * Returns a string representation of the name by imploding the namespace parts with the
     * namespace separator.
     *
     * @return string String representation
     */
    public function __toString(): string {
        return $this->name;
    }

    /**
     * Gets a slice of a name (similar to array_slice).
     *
     * This method returns a new instance of the same type as the original and with the same
     * attributes.
     *
     * If the slice is empty, null is returned. The null value will be correctly handled in
     * concatenations using concat().
     *
     * Offset and length have the same meaning as in array_slice().
     *
     * @param int $offset Offset to start the slice at (may be negative)
     * @param int|null $length Length of the slice (may be negative)
     *
     * @return static|null Sliced name
     */
    public function slice(int $offset, ?int $length = null) {
        if ($offset === 1 && $length === null) {
            // Short-circuit the common case.
            if (false !== $pos = \strpos($this->name, '\\')) {
                return new static(\substr($this->name, $pos + 1));
            }
            return null;
        }

        $parts = \explode('\\', $this->name);
        $numParts = \count($parts);

        $realOffset = $offset < 0 ? $offset + $numParts : $offset;
        if ($realOffset < 0 || $realOffset > $numParts) {
            throw new \OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset));
        }

        if (null === $length) {
            $realLength = $numParts - $realOffset;
        } else {
            $realLength = $length < 0 ? $length + $numParts - $realOffset : $length;
            if ($realLength < 0 || $realLength > $numParts - $realOffset) {
                throw new \OutOfBoundsException(sprintf('Length %d is out of bounds', $length));
            }
        }

        if ($realLength === 0) {
            // Empty slice is represented as null
            return null;
        }

        return new static(array_slice($parts, $realOffset, $realLength), $this->attributes);
    }

    /**
     * Concatenate two names, yielding a new Name instance.
     *
     * The type of the generated instance depends on which class this method is called on, for
     * example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
     *
     * If one of the arguments is null, a new instance of the other name will be returned. If both
     * arguments are null, null will be returned. As such, writing
     *     Name::concat($namespace, $shortName)
     * where $namespace is a Name node or null will work as expected.
     *
     * @param string|string[]|self|null $name1 The first name
     * @param string|string[]|self|null $name2 The second name
     * @param array<string, mixed> $attributes Attributes to assign to concatenated name
     *
     * @return static|null Concatenated name
     */
    public static function concat($name1, $name2, array $attributes = []) {
        if (null === $name1 && null === $name2) {
            return null;
        }
        if (null === $name1) {
            return new static($name2, $attributes);
        }
        if (null === $name2) {
            return new static($name1, $attributes);
        } else {
            return new static(
                self::prepareName($name1) . '\\' . self::prepareName($name2), $attributes
            );
        }
    }

    /**
     * Prepares a (string, array or Name node) name for use in name changing methods by converting
     * it to a string.
     *
     * @param string|string[]|self $name Name to prepare
     *
     * @return string Prepared name
     */
    private static function prepareName($name): string {
        if (\is_string($name)) {
            if ('' === $name) {
                throw new \InvalidArgumentException('Name cannot be empty');
            }

            return $name;
        }
        if (\is_array($name)) {
            if (empty($name)) {
                throw new \InvalidArgumentException('Name cannot be empty');
            }

            return implode('\\', $name);
        }
        if ($name instanceof self) {
            return $name->name;
        }

        throw new \InvalidArgumentException(
            'Expected string, array of parts or Name instance'
        );
    }

    public function getType(): string {
        return 'Name';
    }
}
Node/ComplexType.php000064400000000503151520657540010423 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

/**
 * This is a base class for complex types, including nullable types and union types.
 *
 * It does not provide any shared behavior and exists only for type-checking purposes.
 */
abstract class ComplexType extends NodeAbstract {
}
Node/Scalar.php000064400000000142151520657540007356 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

abstract class Scalar extends Expr {
}
Node/NullableType.php000064400000001247151520657540010560 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;

class NullableType extends ComplexType {
    /** @var Identifier|Name Type */
    public Node $type;

    /**
     * Constructs a nullable type (wrapping another type).
     *
     * @param Identifier|Name $type Type
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $type, array $attributes = []) {
        $this->attributes = $attributes;
        $this->type = $type;
    }

    public function getSubNodeNames(): array {
        return ['type'];
    }

    public function getType(): string {
        return 'NullableType';
    }
}
Node/UseItem.php000064400000003215151520657540007530 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;
use PhpParser\Node\Stmt\Use_;

class UseItem extends NodeAbstract {
    /**
     * @var Use_::TYPE_* One of the Stmt\Use_::TYPE_* constants. Will only differ from TYPE_UNKNOWN for mixed group uses
     */
    public int $type;
    /** @var Node\Name Namespace, class, function or constant to alias */
    public Name $name;
    /** @var Identifier|null Alias */
    public ?Identifier $alias;

    /**
     * Constructs an alias (use) item node.
     *
     * @param Node\Name $name Namespace/Class to alias
     * @param null|string|Identifier $alias Alias
     * @param Use_::TYPE_* $type Type of the use element (for mixed group use only)
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Name $name, $alias = null, int $type = Use_::TYPE_UNKNOWN, array $attributes = []) {
        $this->attributes = $attributes;
        $this->type = $type;
        $this->name = $name;
        $this->alias = \is_string($alias) ? new Identifier($alias) : $alias;
    }

    public function getSubNodeNames(): array {
        return ['type', 'name', 'alias'];
    }

    /**
     * Get alias. If not explicitly given this is the last component of the used name.
     */
    public function getAlias(): Identifier {
        if (null !== $this->alias) {
            return $this->alias;
        }

        return new Identifier($this->name->getLast());
    }

    public function getType(): string {
        return 'UseItem';
    }
}

// @deprecated compatibility alias
class_alias(UseItem::class, Stmt\UseUse::class);
Node/MatchArm.php000064400000001246151520657540007653 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\Node;
use PhpParser\NodeAbstract;

class MatchArm extends NodeAbstract {
    /** @var null|list<Node\Expr> */
    public ?array $conds;
    /** @var Node\Expr */
    public Expr $body;

    /**
     * @param null|list<Node\Expr> $conds
     */
    public function __construct(?array $conds, Node\Expr $body, array $attributes = []) {
        $this->conds = $conds;
        $this->body = $body;
        $this->attributes = $attributes;
    }

    public function getSubNodeNames(): array {
        return ['conds', 'body'];
    }

    public function getType(): string {
        return 'MatchArm';
    }
}
Node/ClosureUse.php000064400000001715151520657540010251 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class ClosureUse extends NodeAbstract {
    /** @var Expr\Variable Variable to use */
    public Expr\Variable $var;
    /** @var bool Whether to use by reference */
    public bool $byRef;

    /**
     * Constructs a closure use node.
     *
     * @param Expr\Variable $var Variable to use
     * @param bool $byRef Whether to use by reference
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr\Variable $var, bool $byRef = false, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->byRef = $byRef;
    }

    public function getSubNodeNames(): array {
        return ['var', 'byRef'];
    }

    public function getType(): string {
        return 'ClosureUse';
    }
}

// @deprecated compatibility alias
class_alias(ClosureUse::class, Expr\ClosureUse::class);
Node/Expr/PreDec.php000064400000001174151520657540010237 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class PreDec extends Expr {
    /** @var Expr Variable */
    public Expr $var;

    /**
     * Constructs a pre decrement node.
     *
     * @param Expr $var Variable
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
    }

    public function getSubNodeNames(): array {
        return ['var'];
    }

    public function getType(): string {
        return 'Expr_PreDec';
    }
}
Node/Expr/ArrayItem.php000064400000000107151520657540010765 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../ArrayItem.php';
Node/Expr/Variable.php000064400000001175151520657540010623 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Variable extends Expr {
    /** @var string|Expr Name */
    public $name;

    /**
     * Constructs a variable node.
     *
     * @param string|Expr $name Name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct($name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    public function getType(): string {
        return 'Expr_Variable';
    }
}
Node/Expr/List_.php000064400000001557151520657540010154 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\ArrayItem;
use PhpParser\Node\Expr;

class List_ extends Expr {
    // For use in "kind" attribute
    public const KIND_LIST = 1; // list() syntax
    public const KIND_ARRAY = 2; // [] syntax

    /** @var (ArrayItem|null)[] List of items to assign to */
    public array $items;

    /**
     * Constructs a list() destructuring node.
     *
     * @param (ArrayItem|null)[] $items List of items to assign to
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $items, array $attributes = []) {
        $this->attributes = $attributes;
        $this->items = $items;
    }

    public function getSubNodeNames(): array {
        return ['items'];
    }

    public function getType(): string {
        return 'Expr_List';
    }
}
Node/Expr/Exit_.php000064400000001366151520657540010150 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Exit_ extends Expr {
    /* For use in "kind" attribute */
    public const KIND_EXIT = 1;
    public const KIND_DIE = 2;

    /** @var null|Expr Expression */
    public ?Expr $expr;

    /**
     * Constructs an exit() node.
     *
     * @param null|Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Expr $expr = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Exit';
    }
}
Node/Expr/Cast/Unset_.php000064400000000322151520657540011216 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Unset_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_Unset';
    }
}
Node/Expr/Cast/String_.php000064400000000324151520657540011370 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class String_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_String';
    }
}
Node/Expr/Cast/Bool_.php000064400000000320151520657540011011 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Bool_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_Bool';
    }
}
Node/Expr/Cast/Array_.php000064400000000322151520657540011176 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Array_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_Array';
    }
}
Node/Expr/Cast/Int_.php000064400000000316151520657540010655 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Int_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_Int';
    }
}
Node/Expr/Cast/Object_.php000064400000000324151520657540011330 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Object_ extends Cast {
    public function getType(): string {
        return 'Expr_Cast_Object';
    }
}
Node/Expr/Cast/Double.php000064400000000621151520657540011175 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\Cast;

use PhpParser\Node\Expr\Cast;

class Double extends Cast {
    // For use in "kind" attribute
    public const KIND_DOUBLE = 1; // "double" syntax
    public const KIND_FLOAT = 2;  // "float" syntax
    public const KIND_REAL = 3; // "real" syntax

    public function getType(): string {
        return 'Expr_Cast_Double';
    }
}
Node/Expr/ArrayDimFetch.php000064400000001466151520657540011563 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class ArrayDimFetch extends Expr {
    /** @var Expr Variable */
    public Expr $var;
    /** @var null|Expr Array index / dim */
    public ?Expr $dim;

    /**
     * Constructs an array index fetch node.
     *
     * @param Expr $var Variable
     * @param null|Expr $dim Array index / dim
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->dim = $dim;
    }

    public function getSubNodeNames(): array {
        return ['var', 'dim'];
    }

    public function getType(): string {
        return 'Expr_ArrayDimFetch';
    }
}
Node/Expr/Include_.php000064400000001667151520657540010626 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Include_ extends Expr {
    public const TYPE_INCLUDE      = 1;
    public const TYPE_INCLUDE_ONCE = 2;
    public const TYPE_REQUIRE      = 3;
    public const TYPE_REQUIRE_ONCE = 4;

    /** @var Expr Expression */
    public Expr $expr;
    /** @var int Type of include */
    public int $type;

    /**
     * Constructs an include node.
     *
     * @param Expr $expr Expression
     * @param int $type Type of include
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, int $type, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
        $this->type = $type;
    }

    public function getSubNodeNames(): array {
        return ['expr', 'type'];
    }

    public function getType(): string {
        return 'Expr_Include';
    }
}
Node/Expr/ConstFetch.php000064400000001253151520657540011133 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;
use PhpParser\Node\Name;

class ConstFetch extends Expr {
    /** @var Name Constant name */
    public Name $name;

    /**
     * Constructs a const fetch node.
     *
     * @param Name $name Constant name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Name $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
    }

    public function getSubNodeNames(): array {
        return ['name'];
    }

    public function getType(): string {
        return 'Expr_ConstFetch';
    }
}
Node/Expr/Instanceof_.php000064400000001534151520657540011325 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;

class Instanceof_ extends Expr {
    /** @var Expr Expression */
    public Expr $expr;
    /** @var Name|Expr Class name */
    public Node $class;

    /**
     * Constructs an instanceof check node.
     *
     * @param Expr $expr Expression
     * @param Name|Expr $class Class name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, Node $class, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
        $this->class = $class;
    }

    public function getSubNodeNames(): array {
        return ['expr', 'class'];
    }

    public function getType(): string {
        return 'Expr_Instanceof';
    }
}
Node/Expr/Ternary.php000064400000001707151520657540010523 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Ternary extends Expr {
    /** @var Expr Condition */
    public Expr $cond;
    /** @var null|Expr Expression for true */
    public ?Expr $if;
    /** @var Expr Expression for false */
    public Expr $else;

    /**
     * Constructs a ternary operator node.
     *
     * @param Expr $cond Condition
     * @param null|Expr $if Expression for true
     * @param Expr $else Expression for false
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $cond, ?Expr $if, Expr $else, array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->if = $if;
        $this->else = $else;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'if', 'else'];
    }

    public function getType(): string {
        return 'Expr_Ternary';
    }
}
Node/Expr/NullsafeMethodCall.php000064400000002424151520657540012602 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\VariadicPlaceholder;

class NullsafeMethodCall extends CallLike {
    /** @var Expr Variable holding object */
    public Expr $var;
    /** @var Identifier|Expr Method name */
    public Node $name;
    /** @var array<Arg|VariadicPlaceholder> Arguments */
    public array $args;

    /**
     * Constructs a nullsafe method call node.
     *
     * @param Expr $var Variable holding object
     * @param string|Identifier|Expr $name Method name
     * @param array<Arg|VariadicPlaceholder> $args Arguments
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['var', 'name', 'args'];
    }

    public function getType(): string {
        return 'Expr_NullsafeMethodCall';
    }

    public function getRawArgs(): array {
        return $this->args;
    }
}
Node/Expr/UnaryMinus.php000064400000001214151520657540011202 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class UnaryMinus extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a unary minus node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_UnaryMinus';
    }
}
Node/Expr/Print_.php000064400000001200151520657540010316 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Print_ extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs an print() node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Print';
    }
}
Node/Expr/AssignOp.php000064400000001326151520657540010617 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

abstract class AssignOp extends Expr {
    /** @var Expr Variable */
    public Expr $var;
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a compound assignment operation node.
     *
     * @param Expr $var Variable
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['var', 'expr'];
    }
}
Node/Expr/ErrorSuppress.php000064400000001226151520657540011731 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class ErrorSuppress extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs an error suppress node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_ErrorSuppress';
    }
}
Node/Expr/MethodCall.php000064400000002375151520657540011115 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\VariadicPlaceholder;

class MethodCall extends CallLike {
    /** @var Expr Variable holding object */
    public Expr $var;
    /** @var Identifier|Expr Method name */
    public Node $name;
    /** @var array<Arg|VariadicPlaceholder> Arguments */
    public array $args;

    /**
     * Constructs a function call node.
     *
     * @param Expr $var Variable holding object
     * @param string|Identifier|Expr $name Method name
     * @param array<Arg|VariadicPlaceholder> $args Arguments
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['var', 'name', 'args'];
    }

    public function getType(): string {
        return 'Expr_MethodCall';
    }

    public function getRawArgs(): array {
        return $this->args;
    }
}
Node/Expr/CallLike.php000064400000001712151520657540010553 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\VariadicPlaceholder;

abstract class CallLike extends Expr {
    /**
     * Return raw arguments, which may be actual Args, or VariadicPlaceholders for first-class
     * callables.
     *
     * @return array<Arg|VariadicPlaceholder>
     */
    abstract public function getRawArgs(): array;

    /**
     * Returns whether this call expression is actually a first class callable.
     */
    public function isFirstClassCallable(): bool {
        $rawArgs = $this->getRawArgs();
        return count($rawArgs) === 1 && current($rawArgs) instanceof VariadicPlaceholder;
    }

    /**
     * Assert that this is not a first-class callable and return only ordinary Args.
     *
     * @return Arg[]
     */
    public function getArgs(): array {
        assert(!$this->isFirstClassCallable());
        return $this->getRawArgs();
    }
}
Node/Expr/Assign.php000064400000001406151520657540010317 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Assign extends Expr {
    /** @var Expr Variable */
    public Expr $var;
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs an assignment node.
     *
     * @param Expr $var Variable
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['var', 'expr'];
    }

    public function getType(): string {
        return 'Expr_Assign';
    }
}
Node/Expr/Error.php000064400000001365151520657540010170 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

/**
 * Error node used during parsing with error recovery.
 *
 * An error node may be placed at a position where an expression is required, but an error occurred.
 * Error nodes will not be present if the parser is run in throwOnError mode (the default).
 */
class Error extends Expr {
    /**
     * Constructs an error node.
     *
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $attributes = []) {
        $this->attributes = $attributes;
    }

    public function getSubNodeNames(): array {
        return [];
    }

    public function getType(): string {
        return 'Expr_Error';
    }
}
Node/Expr/Clone_.php000064400000001175151520657540010275 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Clone_ extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a clone node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Clone';
    }
}
Node/Expr/Array_.php000064400000001477151520657540010320 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\ArrayItem;
use PhpParser\Node\Expr;

class Array_ extends Expr {
    // For use in "kind" attribute
    public const KIND_LONG = 1;  // array() syntax
    public const KIND_SHORT = 2; // [] syntax

    /** @var ArrayItem[] Items */
    public array $items;

    /**
     * Constructs an array node.
     *
     * @param ArrayItem[] $items Items of the array
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $items = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->items = $items;
    }

    public function getSubNodeNames(): array {
        return ['items'];
    }

    public function getType(): string {
        return 'Expr_Array';
    }
}
Node/Expr/NullsafePropertyFetch.php000064400000001713151520657540013364 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;

class NullsafePropertyFetch extends Expr {
    /** @var Expr Variable holding object */
    public Expr $var;
    /** @var Identifier|Expr Property name */
    public Node $name;

    /**
     * Constructs a nullsafe property fetch node.
     *
     * @param Expr $var Variable holding object
     * @param string|Identifier|Expr $name Property name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['var', 'name'];
    }

    public function getType(): string {
        return 'Expr_NullsafePropertyFetch';
    }
}
Node/Expr/Isset_.php000064400000001202151520657540010313 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Isset_ extends Expr {
    /** @var Expr[] Variables */
    public array $vars;

    /**
     * Constructs an array node.
     *
     * @param Expr[] $vars Variables
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $vars, array $attributes = []) {
        $this->attributes = $attributes;
        $this->vars = $vars;
    }

    public function getSubNodeNames(): array {
        return ['vars'];
    }

    public function getType(): string {
        return 'Expr_Isset';
    }
}
Node/Expr/Empty_.php000064400000001200151520657540010320 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Empty_ extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs an empty() node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Empty';
    }
}
Node/Expr/BooleanNot.php000064400000001214151520657540011130 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class BooleanNot extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a boolean not node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_BooleanNot';
    }
}
Node/Expr/ShellExec.php000064400000001433151520657540010747 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;
use PhpParser\Node\InterpolatedStringPart;

class ShellExec extends Expr {
    /** @var (Expr|InterpolatedStringPart)[] Interpolated string array */
    public array $parts;

    /**
     * Constructs a shell exec (backtick) node.
     *
     * @param (Expr|InterpolatedStringPart)[] $parts Interpolated string array
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $parts, array $attributes = []) {
        $this->attributes = $attributes;
        $this->parts = $parts;
    }

    public function getSubNodeNames(): array {
        return ['parts'];
    }

    public function getType(): string {
        return 'Expr_ShellExec';
    }
}
Node/Expr/Throw_.php000064400000001234151520657540010334 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;

class Throw_ extends Node\Expr {
    /** @var Node\Expr Expression */
    public Node\Expr $expr;

    /**
     * Constructs a throw expression node.
     *
     * @param Node\Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Throw';
    }
}
Node/Expr/Cast.php000064400000001067151520657540007770 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

abstract class Cast extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a cast node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }
}
Node/Expr/PreInc.php000064400000001174151520657540010255 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class PreInc extends Expr {
    /** @var Expr Variable */
    public Expr $var;

    /**
     * Constructs a pre increment node.
     *
     * @param Expr $var Variable
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
    }

    public function getSubNodeNames(): array {
        return ['var'];
    }

    public function getType(): string {
        return 'Expr_PreInc';
    }
}
Node/Expr/StaticCall.php000064400000002410151520657540011112 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\VariadicPlaceholder;

class StaticCall extends CallLike {
    /** @var Node\Name|Expr Class name */
    public Node $class;
    /** @var Identifier|Expr Method name */
    public Node $name;
    /** @var array<Arg|VariadicPlaceholder> Arguments */
    public array $args;

    /**
     * Constructs a static method call node.
     *
     * @param Node\Name|Expr $class Class name
     * @param string|Identifier|Expr $name Method name
     * @param array<Arg|VariadicPlaceholder> $args Arguments
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $class, $name, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->class = $class;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['class', 'name', 'args'];
    }

    public function getType(): string {
        return 'Expr_StaticCall';
    }

    public function getRawArgs(): array {
        return $this->args;
    }
}
Node/Expr/BinaryOp.php000064400000002107151520657540010615 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

abstract class BinaryOp extends Expr {
    /** @var Expr The left hand side expression */
    public Expr $left;
    /** @var Expr The right hand side expression */
    public Expr $right;

    /**
     * Constructs a binary operator node.
     *
     * @param Expr $left The left hand side expression
     * @param Expr $right The right hand side expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $left, Expr $right, array $attributes = []) {
        $this->attributes = $attributes;
        $this->left = $left;
        $this->right = $right;
    }

    public function getSubNodeNames(): array {
        return ['left', 'right'];
    }

    /**
     * Get the operator sigil for this binary operation.
     *
     * In the case there are multiple possible sigils for an operator, this method does not
     * necessarily return the one used in the parsed code.
     */
    abstract public function getOperatorSigil(): string;
}
Node/Expr/UnaryPlus.php000064400000001211151520657540011027 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class UnaryPlus extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a unary plus node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_UnaryPlus';
    }
}
Node/Expr/StaticPropertyFetch.php000064400000001766151520657540013052 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\VarLikeIdentifier;

class StaticPropertyFetch extends Expr {
    /** @var Name|Expr Class name */
    public Node $class;
    /** @var VarLikeIdentifier|Expr Property name */
    public Node $name;

    /**
     * Constructs a static property fetch node.
     *
     * @param Name|Expr $class Class name
     * @param string|VarLikeIdentifier|Expr $name Property name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $class, $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->class = $class;
        $this->name = \is_string($name) ? new VarLikeIdentifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['class', 'name'];
    }

    public function getType(): string {
        return 'Expr_StaticPropertyFetch';
    }
}
Node/Expr/BinaryOp/LogicalXor.php000064400000000471151520657540012662 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class LogicalXor extends BinaryOp {
    public function getOperatorSigil(): string {
        return 'xor';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_LogicalXor';
    }
}
Node/Expr/BinaryOp/NotEqual.php000064400000000464151520657540012351 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class NotEqual extends BinaryOp {
    public function getOperatorSigil(): string {
        return '!=';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_NotEqual';
    }
}
Node/Expr/BinaryOp/ShiftRight.php000064400000000470151520657540012671 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class ShiftRight extends BinaryOp {
    public function getOperatorSigil(): string {
        return '>>';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_ShiftRight';
    }
}
Node/Expr/BinaryOp/Smaller.php000064400000000461151520657540012215 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Smaller extends BinaryOp {
    public function getOperatorSigil(): string {
        return '<';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Smaller';
    }
}
Node/Expr/BinaryOp/Spaceship.php000064400000000467151520657540012543 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Spaceship extends BinaryOp {
    public function getOperatorSigil(): string {
        return '<=>';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Spaceship';
    }
}
Node/Expr/BinaryOp/Coalesce.php000064400000000464151520657540012337 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Coalesce extends BinaryOp {
    public function getOperatorSigil(): string {
        return '??';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Coalesce';
    }
}
Node/Expr/BinaryOp/Div.php000064400000000451151520657540011337 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Div extends BinaryOp {
    public function getOperatorSigil(): string {
        return '/';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Div';
    }
}
Node/Expr/BinaryOp/Plus.php000064400000000453151520657540011542 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Plus extends BinaryOp {
    public function getOperatorSigil(): string {
        return '+';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Plus';
    }
}
Node/Expr/BinaryOp/Identical.php000064400000000467151520657540012520 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Identical extends BinaryOp {
    public function getOperatorSigil(): string {
        return '===';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Identical';
    }
}
Node/Expr/BinaryOp/Concat.php000064400000000457151520657540012032 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Concat extends BinaryOp {
    public function getOperatorSigil(): string {
        return '.';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Concat';
    }
}
Node/Expr/BinaryOp/Equal.php000064400000000456151520657540011671 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Equal extends BinaryOp {
    public function getOperatorSigil(): string {
        return '==';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Equal';
    }
}
Node/Expr/BinaryOp/GreaterOrEqual.php000064400000000500151520657540013472 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class GreaterOrEqual extends BinaryOp {
    public function getOperatorSigil(): string {
        return '>=';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_GreaterOrEqual';
    }
}
Node/Expr/BinaryOp/LogicalAnd.php000064400000000471151520657540012614 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class LogicalAnd extends BinaryOp {
    public function getOperatorSigil(): string {
        return 'and';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_LogicalAnd';
    }
}
Node/Expr/BinaryOp/SmallerOrEqual.php000064400000000500151520657540013500 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class SmallerOrEqual extends BinaryOp {
    public function getOperatorSigil(): string {
        return '<=';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_SmallerOrEqual';
    }
}
Node/Expr/BinaryOp/BooleanAnd.php000064400000000470151520657540012620 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class BooleanAnd extends BinaryOp {
    public function getOperatorSigil(): string {
        return '&&';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_BooleanAnd';
    }
}
Node/Expr/BinaryOp/BitwiseOr.php000064400000000465151520657540012531 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class BitwiseOr extends BinaryOp {
    public function getOperatorSigil(): string {
        return '|';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_BitwiseOr';
    }
}
Node/Expr/BinaryOp/Mul.php000064400000000451151520657540011352 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Mul extends BinaryOp {
    public function getOperatorSigil(): string {
        return '*';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Mul';
    }
}
Node/Expr/BinaryOp/Pow.php000064400000000452151520657540011363 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Pow extends BinaryOp {
    public function getOperatorSigil(): string {
        return '**';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Pow';
    }
}
Node/Expr/BinaryOp/NotIdentical.php000064400000000475151520657540013200 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class NotIdentical extends BinaryOp {
    public function getOperatorSigil(): string {
        return '!==';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_NotIdentical';
    }
}
Node/Expr/BinaryOp/BitwiseAnd.php000064400000000467151520657540012655 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class BitwiseAnd extends BinaryOp {
    public function getOperatorSigil(): string {
        return '&';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_BitwiseAnd';
    }
}
Node/Expr/BinaryOp/LogicalOr.php000064400000000466151520657540012476 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class LogicalOr extends BinaryOp {
    public function getOperatorSigil(): string {
        return 'or';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_LogicalOr';
    }
}
Node/Expr/BinaryOp/BooleanOr.php000064400000000466151520657540012503 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class BooleanOr extends BinaryOp {
    public function getOperatorSigil(): string {
        return '||';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_BooleanOr';
    }
}
Node/Expr/BinaryOp/Greater.php000064400000000461151520657540012207 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Greater extends BinaryOp {
    public function getOperatorSigil(): string {
        return '>';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Greater';
    }
}
Node/Expr/BinaryOp/ShiftLeft.php000064400000000466151520657540012513 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class ShiftLeft extends BinaryOp {
    public function getOperatorSigil(): string {
        return '<<';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_ShiftLeft';
    }
}
Node/Expr/BinaryOp/Minus.php000064400000000455151520657540011714 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Minus extends BinaryOp {
    public function getOperatorSigil(): string {
        return '-';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Minus';
    }
}
Node/Expr/BinaryOp/Mod.php000064400000000451151520657540011334 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class Mod extends BinaryOp {
    public function getOperatorSigil(): string {
        return '%';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_Mod';
    }
}
Node/Expr/BinaryOp/BitwiseXor.php000064400000000467151520657540012723 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\BinaryOp;

use PhpParser\Node\Expr\BinaryOp;

class BitwiseXor extends BinaryOp {
    public function getOperatorSigil(): string {
        return '^';
    }

    public function getType(): string {
        return 'Expr_BinaryOp_BitwiseXor';
    }
}
Node/Expr/Eval_.php000064400000001175151520657540010124 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Eval_ extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs an eval() node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_Eval';
    }
}
Node/Expr/ArrowFunction.php000064400000004770151520657540011702 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\FunctionLike;

class ArrowFunction extends Expr implements FunctionLike {
    /** @var bool Whether the closure is static */
    public bool $static;

    /** @var bool Whether to return by reference */
    public bool $byRef;

    /** @var Node\Param[] */
    public array $params = [];

    /** @var null|Node\Identifier|Node\Name|Node\ComplexType */
    public ?Node $returnType;

    /** @var Expr Expression body */
    public Expr $expr;
    /** @var Node\AttributeGroup[] */
    public array $attrGroups;

    /**
     * @param array{
     *     expr: Expr,
     *     static?: bool,
     *     byRef?: bool,
     *     params?: Node\Param[],
     *     returnType?: null|Node\Identifier|Node\Name|Node\ComplexType,
     *     attrGroups?: Node\AttributeGroup[]
     * } $subNodes Array of the following subnodes:
     *             'expr'                  : Expression body
     *             'static'     => false   : Whether the closure is static
     *             'byRef'      => false   : Whether to return by reference
     *             'params'     => array() : Parameters
     *             'returnType' => null    : Return type
     *             'attrGroups' => array() : PHP attribute groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $subNodes, array $attributes = []) {
        $this->attributes = $attributes;
        $this->static = $subNodes['static'] ?? false;
        $this->byRef = $subNodes['byRef'] ?? false;
        $this->params = $subNodes['params'] ?? [];
        $this->returnType = $subNodes['returnType'] ?? null;
        $this->expr = $subNodes['expr'];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr'];
    }

    public function returnsByRef(): bool {
        return $this->byRef;
    }

    public function getParams(): array {
        return $this->params;
    }

    public function getReturnType() {
        return $this->returnType;
    }

    public function getAttrGroups(): array {
        return $this->attrGroups;
    }

    /**
     * @return Node\Stmt\Return_[]
     */
    public function getStmts(): array {
        return [new Node\Stmt\Return_($this->expr)];
    }

    public function getType(): string {
        return 'Expr_ArrowFunction';
    }
}
Node/Expr/Closure.php000064400000005424151520657540010513 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\ClosureUse;
use PhpParser\Node\Expr;
use PhpParser\Node\FunctionLike;

class Closure extends Expr implements FunctionLike {
    /** @var bool Whether the closure is static */
    public bool $static;
    /** @var bool Whether to return by reference */
    public bool $byRef;
    /** @var Node\Param[] Parameters */
    public array $params;
    /** @var ClosureUse[] use()s */
    public array $uses;
    /** @var null|Node\Identifier|Node\Name|Node\ComplexType Return type */
    public ?Node $returnType;
    /** @var Node\Stmt[] Statements */
    public array $stmts;
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;

    /**
     * Constructs a lambda function node.
     *
     * @param array{
     *     static?: bool,
     *     byRef?: bool,
     *     params?: Node\Param[],
     *     uses?: ClosureUse[],
     *     returnType?: null|Node\Identifier|Node\Name|Node\ComplexType,
     *     stmts?: Node\Stmt[],
     *     attrGroups?: Node\AttributeGroup[],
     * } $subNodes Array of the following optional subnodes:
     *             'static'     => false  : Whether the closure is static
     *             'byRef'      => false  : Whether to return by reference
     *             'params'     => array(): Parameters
     *             'uses'       => array(): use()s
     *             'returnType' => null   : Return type
     *             'stmts'      => array(): Statements
     *             'attrGroups' => array(): PHP attributes groups
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(array $subNodes = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->static = $subNodes['static'] ?? false;
        $this->byRef = $subNodes['byRef'] ?? false;
        $this->params = $subNodes['params'] ?? [];
        $this->uses = $subNodes['uses'] ?? [];
        $this->returnType = $subNodes['returnType'] ?? null;
        $this->stmts = $subNodes['stmts'] ?? [];
        $this->attrGroups = $subNodes['attrGroups'] ?? [];
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts'];
    }

    public function returnsByRef(): bool {
        return $this->byRef;
    }

    public function getParams(): array {
        return $this->params;
    }

    public function getReturnType() {
        return $this->returnType;
    }

    /** @return Node\Stmt[] */
    public function getStmts(): array {
        return $this->stmts;
    }

    public function getAttrGroups(): array {
        return $this->attrGroups;
    }

    public function getType(): string {
        return 'Expr_Closure';
    }
}
Node/Expr/ClassConstFetch.php000064400000001732151520657540012123 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;

class ClassConstFetch extends Expr {
    /** @var Name|Expr Class name */
    public Node $class;
    /** @var Identifier|Expr|Error Constant name */
    public Node $name;

    /**
     * Constructs a class const fetch node.
     *
     * @param Name|Expr $class Class name
     * @param string|Identifier|Expr|Error $name Constant name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $class, $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->class = $class;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['class', 'name'];
    }

    public function getType(): string {
        return 'Expr_ClassConstFetch';
    }
}
Node/Expr/FuncCall.php000064400000001742151520657540010565 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;

class FuncCall extends CallLike {
    /** @var Node\Name|Expr Function name */
    public Node $name;
    /** @var array<Node\Arg|Node\VariadicPlaceholder> Arguments */
    public array $args;

    /**
     * Constructs a function call node.
     *
     * @param Node\Name|Expr $name Function name
     * @param array<Node\Arg|Node\VariadicPlaceholder> $args Arguments
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $name, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->name = $name;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['name', 'args'];
    }

    public function getType(): string {
        return 'Expr_FuncCall';
    }

    public function getRawArgs(): array {
        return $this->args;
    }
}
Node/Expr/ClosureUse.php000064400000000110151520657540011153 0ustar00<?php declare(strict_types=1);

require __DIR__ . '/../ClosureUse.php';
Node/Expr/Match_.php000064400000001416151520657540010267 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\MatchArm;

class Match_ extends Node\Expr {
    /** @var Node\Expr Condition */
    public Node\Expr $cond;
    /** @var MatchArm[] */
    public array $arms;

    /**
     * @param Node\Expr $cond Condition
     * @param MatchArm[] $arms
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node\Expr $cond, array $arms = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->cond = $cond;
        $this->arms = $arms;
    }

    public function getSubNodeNames(): array {
        return ['cond', 'arms'];
    }

    public function getType(): string {
        return 'Expr_Match';
    }
}
Node/Expr/PropertyFetch.php000064400000001661151520657540011674 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;

class PropertyFetch extends Expr {
    /** @var Expr Variable holding object */
    public Expr $var;
    /** @var Identifier|Expr Property name */
    public Node $name;

    /**
     * Constructs a function call node.
     *
     * @param Expr $var Variable holding object
     * @param string|Identifier|Expr $name Property name
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, $name, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->name = \is_string($name) ? new Identifier($name) : $name;
    }

    public function getSubNodeNames(): array {
        return ['var', 'name'];
    }

    public function getType(): string {
        return 'Expr_PropertyFetch';
    }
}
Node/Expr/YieldFrom.php000064400000001232151520657540010762 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class YieldFrom extends Expr {
    /** @var Expr Expression to yield from */
    public Expr $expr;

    /**
     * Constructs an "yield from" node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_YieldFrom';
    }
}
Node/Expr/New_.php000064400000002115151520657540007761 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\VariadicPlaceholder;

class New_ extends CallLike {
    /** @var Node\Name|Expr|Node\Stmt\Class_ Class name */
    public Node $class;
    /** @var array<Arg|VariadicPlaceholder> Arguments */
    public array $args;

    /**
     * Constructs a function call node.
     *
     * @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes)
     * @param array<Arg|VariadicPlaceholder> $args Arguments
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Node $class, array $args = [], array $attributes = []) {
        $this->attributes = $attributes;
        $this->class = $class;
        $this->args = $args;
    }

    public function getSubNodeNames(): array {
        return ['class', 'args'];
    }

    public function getType(): string {
        return 'Expr_New';
    }

    public function getRawArgs(): array {
        return $this->args;
    }
}
Node/Expr/AssignRef.php000064400000001467151520657540010763 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class AssignRef extends Expr {
    /** @var Expr Variable reference is assigned to */
    public Expr $var;
    /** @var Expr Variable which is referenced */
    public Expr $expr;

    /**
     * Constructs an assignment node.
     *
     * @param Expr $var Variable
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['var', 'expr'];
    }

    public function getType(): string {
        return 'Expr_AssignRef';
    }
}
Node/Expr/BitwiseNot.php000064400000001214151520657540011157 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class BitwiseNot extends Expr {
    /** @var Expr Expression */
    public Expr $expr;

    /**
     * Constructs a bitwise not node.
     *
     * @param Expr $expr Expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $expr, array $attributes = []) {
        $this->attributes = $attributes;
        $this->expr = $expr;
    }

    public function getSubNodeNames(): array {
        return ['expr'];
    }

    public function getType(): string {
        return 'Expr_BitwiseNot';
    }
}
Node/Expr/Yield_.php000064400000001516151520657540010302 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class Yield_ extends Expr {
    /** @var null|Expr Key expression */
    public ?Expr $key;
    /** @var null|Expr Value expression */
    public ?Expr $value;

    /**
     * Constructs a yield expression node.
     *
     * @param null|Expr $value Value expression
     * @param null|Expr $key Key expression
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) {
        $this->attributes = $attributes;
        $this->key = $key;
        $this->value = $value;
    }

    public function getSubNodeNames(): array {
        return ['key', 'value'];
    }

    public function getType(): string {
        return 'Expr_Yield';
    }
}
Node/Expr/AssignOp/ShiftRight.php000064400000000353151520657540012671 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class ShiftRight extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_ShiftRight';
    }
}
Node/Expr/AssignOp/Coalesce.php000064400000000347151520657540012337 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Coalesce extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Coalesce';
    }
}
Node/Expr/AssignOp/Div.php000064400000000335151520657540011340 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Div extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Div';
    }
}
Node/Expr/AssignOp/Plus.php000064400000000337151520657540011543 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Plus extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Plus';
    }
}
Node/Expr/AssignOp/Concat.php000064400000000343151520657540012024 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Concat extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Concat';
    }
}
Node/Expr/AssignOp/BitwiseOr.php000064400000000351151520657540012523 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class BitwiseOr extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_BitwiseOr';
    }
}
Node/Expr/AssignOp/Mul.php000064400000000335151520657540011353 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Mul extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Mul';
    }
}
Node/Expr/AssignOp/Pow.php000064400000000335151520657540011363 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Pow extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Pow';
    }
}
Node/Expr/AssignOp/BitwiseAnd.php000064400000000353151520657540012647 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class BitwiseAnd extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_BitwiseAnd';
    }
}
Node/Expr/AssignOp/ShiftLeft.php000064400000000351151520657540012504 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class ShiftLeft extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_ShiftLeft';
    }
}
Node/Expr/AssignOp/Minus.php000064400000000341151520657540011706 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Minus extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Minus';
    }
}
Node/Expr/AssignOp/Mod.php000064400000000335151520657540011335 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class Mod extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_Mod';
    }
}
Node/Expr/AssignOp/BitwiseXor.php000064400000000353151520657540012715 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr\AssignOp;

use PhpParser\Node\Expr\AssignOp;

class BitwiseXor extends AssignOp {
    public function getType(): string {
        return 'Expr_AssignOp_BitwiseXor';
    }
}
Node/Expr/PostInc.php000064400000001177151520657540010457 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class PostInc extends Expr {
    /** @var Expr Variable */
    public Expr $var;

    /**
     * Constructs a post increment node.
     *
     * @param Expr $var Variable
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
    }

    public function getSubNodeNames(): array {
        return ['var'];
    }

    public function getType(): string {
        return 'Expr_PostInc';
    }
}
Node/Expr/PostDec.php000064400000001177151520657540010441 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node\Expr;

use PhpParser\Node\Expr;

class PostDec extends Expr {
    /** @var Expr Variable */
    public Expr $var;

    /**
     * Constructs a post decrement node.
     *
     * @param Expr $var Variable
     * @param array<string, mixed> $attributes Additional attributes
     */
    public function __construct(Expr $var, array $attributes = []) {
        $this->attributes = $attributes;
        $this->var = $var;
    }

    public function getSubNodeNames(): array {
        return ['var'];
    }

    public function getType(): string {
        return 'Expr_PostDec';
    }
}
Node/Expr.php000064400000000205151520657540007067 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

abstract class Expr extends NodeAbstract {
}
Node/Arg.php000064400000002423151520657540006666 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Node;

use PhpParser\NodeAbstract;

class Arg extends NodeAbstract {
    /** @var Identifier|null Parameter name (for named parameters) */
    public ?Identifier $name;
    /** @var Expr Value to pass */
    public Expr $value;
    /** @var bool Whether to pass by ref */
    public bool $byRef;
    /** @var bool Whether to unpack the argument */
    public bool $unpack;

    /**
     * Constructs a function call argument node.
     *
     * @param Expr $value Value to pass
     * @param bool $byRef Whether to pass by ref
     * @param bool $unpack Whether to unpack the argument
     * @param array<string, mixed> $attributes Additional attributes
     * @param Identifier|null $name Parameter name (for named parameters)
     */
    public function __construct(
        Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],
        ?Identifier $name = null
    ) {
        $this->attributes = $attributes;
        $this->name = $name;
        $this->value = $value;
        $this->byRef = $byRef;
        $this->unpack = $unpack;
    }

    public function getSubNodeNames(): array {
        return ['name', 'value', 'byRef', 'unpack'];
    }

    public function getType(): string {
        return 'Arg';
    }
}
Internal/TokenPolyfill.php000064400000022640151520657540011642 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Internal;

if (\PHP_VERSION_ID >= 80000) {
    class TokenPolyfill extends \PhpToken {
    }
    return;
}

/**
 * This is a polyfill for the PhpToken class introduced in PHP 8.0. We do not actually polyfill
 * PhpToken, because composer might end up picking a different polyfill implementation, which does
 * not meet our requirements.
 *
 * @internal
 */
class TokenPolyfill {
    /** @var int The ID of the token. Either a T_* constant of a character code < 256. */
    public int $id;
    /** @var string The textual content of the token. */
    public string $text;
    /** @var int The 1-based starting line of the token (or -1 if unknown). */
    public int $line;
    /** @var int The 0-based starting position of the token (or -1 if unknown). */
    public int $pos;

    /** @var array<int, bool> Tokens ignored by the PHP parser. */
    private const IGNORABLE_TOKENS = [
        \T_WHITESPACE => true,
        \T_COMMENT => true,
        \T_DOC_COMMENT => true,
        \T_OPEN_TAG => true,
    ];

    /** @var array<int, bool> Tokens that may be part of a T_NAME_* identifier. */
    private static array $identifierTokens;

    /**
     * Create a Token with the given ID and text, as well optional line and position information.
     */
    final public function __construct(int $id, string $text, int $line = -1, int $pos = -1) {
        $this->id = $id;
        $this->text = $text;
        $this->line = $line;
        $this->pos = $pos;
    }

    /**
     * Get the name of the token. For single-char tokens this will be the token character.
     * Otherwise it will be a T_* style name, or null if the token ID is unknown.
     */
    public function getTokenName(): ?string {
        if ($this->id < 256) {
            return \chr($this->id);
        }

        $name = token_name($this->id);
        return $name === 'UNKNOWN' ? null : $name;
    }

    /**
     * Check whether the token is of the given kind. The kind may be either an integer that matches
     * the token ID, a string that matches the token text, or an array of integers/strings. In the
     * latter case, the function returns true if any of the kinds in the array match.
     *
     * @param int|string|(int|string)[] $kind
     */
    public function is($kind): bool {
        if (\is_int($kind)) {
            return $this->id === $kind;
        }
        if (\is_string($kind)) {
            return $this->text === $kind;
        }
        if (\is_array($kind)) {
            foreach ($kind as $entry) {
                if (\is_int($entry)) {
                    if ($this->id === $entry) {
                        return true;
                    }
                } elseif (\is_string($entry)) {
                    if ($this->text === $entry) {
                        return true;
                    }
                } else {
                    throw new \TypeError(
                        'Argument #1 ($kind) must only have elements of type string|int, ' .
                        gettype($entry) . ' given');
                }
            }
            return false;
        }
        throw new \TypeError(
            'Argument #1 ($kind) must be of type string|int|array, ' .gettype($kind) . ' given');
    }

    /**
     * Check whether this token would be ignored by the PHP parser. Returns true for T_WHITESPACE,
     * T_COMMENT, T_DOC_COMMENT and T_OPEN_TAG, and false for everything else.
     */
    public function isIgnorable(): bool {
        return isset(self::IGNORABLE_TOKENS[$this->id]);
    }

    /**
     * Return the textual content of the token.
     */
    public function __toString(): string {
        return $this->text;
    }

    /**
     * Tokenize the given source code and return an array of tokens.
     *
     * This performs certain canonicalizations to match the PHP 8.0 token format:
     *  * Bad characters are represented using T_BAD_CHARACTER rather than omitted.
     *  * T_COMMENT does not include trailing newlines, instead the newline is part of a following
     *    T_WHITESPACE token.
     *  * Namespaced names are represented using T_NAME_* tokens.
     *
     * @return static[]
     */
    public static function tokenize(string $code, int $flags = 0): array {
        self::init();

        $tokens = [];
        $line = 1;
        $pos = 0;
        $origTokens = \token_get_all($code, $flags);

        $numTokens = \count($origTokens);
        for ($i = 0; $i < $numTokens; $i++) {
            $token = $origTokens[$i];
            if (\is_string($token)) {
                if (\strlen($token) === 2) {
                    // b" and B" are tokenized as single-char tokens, even though they aren't.
                    $tokens[] = new static(\ord('"'), $token, $line, $pos);
                    $pos += 2;
                } else {
                    $tokens[] = new static(\ord($token), $token, $line, $pos);
                    $pos++;
                }
            } else {
                $id = $token[0];
                $text = $token[1];

                // Emulate PHP 8.0 comment format, which does not include trailing whitespace anymore.
                if ($id === \T_COMMENT && \substr($text, 0, 2) !== '/*' &&
                    \preg_match('/(\r\n|\n|\r)$/D', $text, $matches)
                ) {
                    $trailingNewline = $matches[0];
                    $text = \substr($text, 0, -\strlen($trailingNewline));
                    $tokens[] = new static($id, $text, $line, $pos);
                    $pos += \strlen($text);

                    if ($i + 1 < $numTokens && $origTokens[$i + 1][0] === \T_WHITESPACE) {
                        // Move trailing newline into following T_WHITESPACE token, if it already exists.
                        $origTokens[$i + 1][1] = $trailingNewline . $origTokens[$i + 1][1];
                        $origTokens[$i + 1][2]--;
                    } else {
                        // Otherwise, we need to create a new T_WHITESPACE token.
                        $tokens[] = new static(\T_WHITESPACE, $trailingNewline, $line, $pos);
                        $line++;
                        $pos += \strlen($trailingNewline);
                    }
                    continue;
                }

                // Emulate PHP 8.0 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and
                // T_STRING into a single token.
                if (($id === \T_NS_SEPARATOR || isset(self::$identifierTokens[$id]))) {
                    $newText = $text;
                    $lastWasSeparator = $id === \T_NS_SEPARATOR;
                    for ($j = $i + 1; $j < $numTokens; $j++) {
                        if ($lastWasSeparator) {
                            if (!isset(self::$identifierTokens[$origTokens[$j][0]])) {
                                break;
                            }
                            $lastWasSeparator = false;
                        } else {
                            if ($origTokens[$j][0] !== \T_NS_SEPARATOR) {
                                break;
                            }
                            $lastWasSeparator = true;
                        }
                        $newText .= $origTokens[$j][1];
                    }
                    if ($lastWasSeparator) {
                        // Trailing separator is not part of the name.
                        $j--;
                        $newText = \substr($newText, 0, -1);
                    }
                    if ($j > $i + 1) {
                        if ($id === \T_NS_SEPARATOR) {
                            $id = \T_NAME_FULLY_QUALIFIED;
                        } elseif ($id === \T_NAMESPACE) {
                            $id = \T_NAME_RELATIVE;
                        } else {
                            $id = \T_NAME_QUALIFIED;
                        }
                        $tokens[] = new static($id, $newText, $line, $pos);
                        $pos += \strlen($newText);
                        $i = $j - 1;
                        continue;
                    }
                }

                $tokens[] = new static($id, $text, $line, $pos);
                $line += \substr_count($text, "\n");
                $pos += \strlen($text);
            }
        }
        return $tokens;
    }

    /** Initialize private static state needed by tokenize(). */
    private static function init(): void {
        if (isset(self::$identifierTokens)) {
            return;
        }

        // Based on semi_reserved production.
        self::$identifierTokens = \array_fill_keys([
            \T_STRING,
            \T_STATIC, \T_ABSTRACT, \T_FINAL, \T_PRIVATE, \T_PROTECTED, \T_PUBLIC, \T_READONLY,
            \T_INCLUDE, \T_INCLUDE_ONCE, \T_EVAL, \T_REQUIRE, \T_REQUIRE_ONCE, \T_LOGICAL_OR, \T_LOGICAL_XOR, \T_LOGICAL_AND,
            \T_INSTANCEOF, \T_NEW, \T_CLONE, \T_EXIT, \T_IF, \T_ELSEIF, \T_ELSE, \T_ENDIF, \T_ECHO, \T_DO, \T_WHILE,
            \T_ENDWHILE, \T_FOR, \T_ENDFOR, \T_FOREACH, \T_ENDFOREACH, \T_DECLARE, \T_ENDDECLARE, \T_AS, \T_TRY, \T_CATCH,
            \T_FINALLY, \T_THROW, \T_USE, \T_INSTEADOF, \T_GLOBAL, \T_VAR, \T_UNSET, \T_ISSET, \T_EMPTY, \T_CONTINUE, \T_GOTO,
            \T_FUNCTION, \T_CONST, \T_RETURN, \T_PRINT, \T_YIELD, \T_LIST, \T_SWITCH, \T_ENDSWITCH, \T_CASE, \T_DEFAULT,
            \T_BREAK, \T_ARRAY, \T_CALLABLE, \T_EXTENDS, \T_IMPLEMENTS, \T_NAMESPACE, \T_TRAIT, \T_INTERFACE, \T_CLASS,
            \T_CLASS_C, \T_TRAIT_C, \T_FUNC_C, \T_METHOD_C, \T_LINE, \T_FILE, \T_DIR, \T_NS_C, \T_HALT_COMPILER, \T_FN,
            \T_MATCH,
        ], true);
    }
}
Internal/PrintableNewAnonClassNode.php000064400000005155151520657540014053 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Internal;

use PhpParser\Node;
use PhpParser\Node\Expr;

/**
 * This node is used internally by the format-preserving pretty printer to print anonymous classes.
 *
 * The normal anonymous class structure violates assumptions about the order of token offsets.
 * Namely, the constructor arguments are part of the Expr\New_ node and follow the class node, even
 * though they are actually interleaved with them. This special node type is used temporarily to
 * restore a sane token offset order.
 *
 * @internal
 */
class PrintableNewAnonClassNode extends Expr {
    /** @var Node\AttributeGroup[] PHP attribute groups */
    public array $attrGroups;
    /** @var int Modifiers */
    public int $flags;
    /** @var (Node\Arg|Node\VariadicPlaceholder)[] Arguments */
    public array $args;
    /** @var null|Node\Name Name of extended class */
    public ?Node\Name $extends;
    /** @var Node\Name[] Names of implemented interfaces */
    public array $implements;
    /** @var Node\Stmt[] Statements */
    public array $stmts;

    /**
     * @param Node\AttributeGroup[] $attrGroups PHP attribute groups
     * @param (Node\Arg|Node\VariadicPlaceholder)[] $args Arguments
     * @param Node\Name|null $extends Name of extended class
     * @param Node\Name[] $implements Names of implemented interfaces
     * @param Node\Stmt[] $stmts Statements
     * @param array<string, mixed> $attributes Attributes
     */
    public function __construct(
        array $attrGroups, int $flags, array $args, ?Node\Name $extends, array $implements,
        array $stmts, array $attributes
    ) {
        parent::__construct($attributes);
        $this->attrGroups = $attrGroups;
        $this->flags = $flags;
        $this->args = $args;
        $this->extends = $extends;
        $this->implements = $implements;
        $this->stmts = $stmts;
    }

    public static function fromNewNode(Expr\New_ $newNode): self {
        $class = $newNode->class;
        assert($class instanceof Node\Stmt\Class_);
        // We don't assert that $class->name is null here, to allow consumers to assign unique names
        // to anonymous classes for their own purposes. We simplify ignore the name here.
        return new self(
            $class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,
            $class->stmts, $newNode->getAttributes()
        );
    }

    public function getType(): string {
        return 'Expr_PrintableNewAnonClass';
    }

    public function getSubNodeNames(): array {
        return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];
    }
}
Internal/Differ.php000064400000011745151520657540010252 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Internal;

/**
 * Implements the Myers diff algorithm.
 *
 * Myers, Eugene W. "An O (ND) difference algorithm and its variations."
 * Algorithmica 1.1 (1986): 251-266.
 *
 * @template T
 * @internal
 */
class Differ {
    /** @var callable(T, T): bool */
    private $isEqual;

    /**
     * Create differ over the given equality relation.
     *
     * @param callable(T, T): bool $isEqual Equality relation
     */
    public function __construct(callable $isEqual) {
        $this->isEqual = $isEqual;
    }

    /**
     * Calculate diff (edit script) from $old to $new.
     *
     * @param T[] $old Original array
     * @param T[] $new New array
     *
     * @return DiffElem[] Diff (edit script)
     */
    public function diff(array $old, array $new): array {
        $old = \array_values($old);
        $new = \array_values($new);
        list($trace, $x, $y) = $this->calculateTrace($old, $new);
        return $this->extractDiff($trace, $x, $y, $old, $new);
    }

    /**
     * Calculate diff, including "replace" operations.
     *
     * If a sequence of remove operations is followed by the same number of add operations, these
     * will be coalesced into replace operations.
     *
     * @param T[] $old Original array
     * @param T[] $new New array
     *
     * @return DiffElem[] Diff (edit script), including replace operations
     */
    public function diffWithReplacements(array $old, array $new): array {
        return $this->coalesceReplacements($this->diff($old, $new));
    }

    /**
     * @param T[] $old
     * @param T[] $new
     * @return array{array<int, array<int, int>>, int, int}
     */
    private function calculateTrace(array $old, array $new): array {
        $n = \count($old);
        $m = \count($new);
        $max = $n + $m;
        $v = [1 => 0];
        $trace = [];
        for ($d = 0; $d <= $max; $d++) {
            $trace[] = $v;
            for ($k = -$d; $k <= $d; $k += 2) {
                if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {
                    $x = $v[$k + 1];
                } else {
                    $x = $v[$k - 1] + 1;
                }

                $y = $x - $k;
                while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) {
                    $x++;
                    $y++;
                }

                $v[$k] = $x;
                if ($x >= $n && $y >= $m) {
                    return [$trace, $x, $y];
                }
            }
        }
        throw new \Exception('Should not happen');
    }

    /**
     * @param array<int, array<int, int>> $trace
     * @param T[] $old
     * @param T[] $new
     * @return DiffElem[]
     */
    private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array {
        $result = [];
        for ($d = \count($trace) - 1; $d >= 0; $d--) {
            $v = $trace[$d];
            $k = $x - $y;

            if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {
                $prevK = $k + 1;
            } else {
                $prevK = $k - 1;
            }

            $prevX = $v[$prevK];
            $prevY = $prevX - $prevK;

            while ($x > $prevX && $y > $prevY) {
                $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]);
                $x--;
                $y--;
            }

            if ($d === 0) {
                break;
            }

            while ($x > $prevX) {
                $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null);
                $x--;
            }

            while ($y > $prevY) {
                $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]);
                $y--;
            }
        }
        return array_reverse($result);
    }

    /**
     * Coalesce equal-length sequences of remove+add into a replace operation.
     *
     * @param DiffElem[] $diff
     * @return DiffElem[]
     */
    private function coalesceReplacements(array $diff): array {
        $newDiff = [];
        $c = \count($diff);
        for ($i = 0; $i < $c; $i++) {
            $diffType = $diff[$i]->type;
            if ($diffType !== DiffElem::TYPE_REMOVE) {
                $newDiff[] = $diff[$i];
                continue;
            }

            $j = $i;
            while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) {
                $j++;
            }

            $k = $j;
            while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) {
                $k++;
            }

            if ($j - $i === $k - $j) {
                $len = $j - $i;
                for ($n = 0; $n < $len; $n++) {
                    $newDiff[] = new DiffElem(
                        DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new
                    );
                }
            } else {
                for (; $i < $k; $i++) {
                    $newDiff[] = $diff[$i];
                }
            }
            $i = $k - 1;
        }
        return $newDiff;
    }
}
Internal/DiffElem.php000064400000001373151520657540010522 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Internal;

/**
 * @internal
 */
class DiffElem {
    public const TYPE_KEEP = 0;
    public const TYPE_REMOVE = 1;
    public const TYPE_ADD = 2;
    public const TYPE_REPLACE = 3;

    /** @var int One of the TYPE_* constants */
    public int $type;
    /** @var mixed Is null for add operations */
    public $old;
    /** @var mixed Is null for remove operations */
    public $new;

    /**
     * @param int $type One of the TYPE_* constants
     * @param mixed $old Is null for add operations
     * @param mixed $new Is null for remove operations
     */
    public function __construct(int $type, $old, $new) {
        $this->type = $type;
        $this->old = $old;
        $this->new = $new;
    }
}
Internal/TokenStream.php000064400000021307151520657540011302 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Internal;

use PhpParser\Token;

/**
 * Provides operations on token streams, for use by pretty printer.
 *
 * @internal
 */
class TokenStream {
    /** @var Token[] Tokens (in PhpToken::tokenize() format) */
    private array $tokens;
    /** @var int[] Map from position to indentation */
    private array $indentMap;

    /**
     * Create token stream instance.
     *
     * @param Token[] $tokens Tokens in PhpToken::tokenize() format
     */
    public function __construct(array $tokens) {
        $this->tokens = $tokens;
        $this->indentMap = $this->calcIndentMap();
    }

    /**
     * Whether the given position is immediately surrounded by parenthesis.
     *
     * @param int $startPos Start position
     * @param int $endPos End position
     */
    public function haveParens(int $startPos, int $endPos): bool {
        return $this->haveTokenImmediatelyBefore($startPos, '(')
            && $this->haveTokenImmediatelyAfter($endPos, ')');
    }

    /**
     * Whether the given position is immediately surrounded by braces.
     *
     * @param int $startPos Start position
     * @param int $endPos End position
     */
    public function haveBraces(int $startPos, int $endPos): bool {
        return ($this->haveTokenImmediatelyBefore($startPos, '{')
                || $this->haveTokenImmediatelyBefore($startPos, T_CURLY_OPEN))
            && $this->haveTokenImmediatelyAfter($endPos, '}');
    }

    /**
     * Check whether the position is directly preceded by a certain token type.
     *
     * During this check whitespace and comments are skipped.
     *
     * @param int $pos Position before which the token should occur
     * @param int|string $expectedTokenType Token to check for
     *
     * @return bool Whether the expected token was found
     */
    public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType): bool {
        $tokens = $this->tokens;
        $pos--;
        for (; $pos >= 0; $pos--) {
            $token = $tokens[$pos];
            if ($token->is($expectedTokenType)) {
                return true;
            }
            if (!$token->isIgnorable()) {
                break;
            }
        }
        return false;
    }

    /**
     * Check whether the position is directly followed by a certain token type.
     *
     * During this check whitespace and comments are skipped.
     *
     * @param int $pos Position after which the token should occur
     * @param int|string $expectedTokenType Token to check for
     *
     * @return bool Whether the expected token was found
     */
    public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType): bool {
        $tokens = $this->tokens;
        $pos++;
        for ($c = \count($tokens); $pos < $c; $pos++) {
            $token = $tokens[$pos];
            if ($token->is($expectedTokenType)) {
                return true;
            }
            if (!$token->isIgnorable()) {
                break;
            }
        }
        return false;
    }

    /** @param int|string|(int|string)[] $skipTokenType */
    public function skipLeft(int $pos, $skipTokenType): int {
        $tokens = $this->tokens;

        $pos = $this->skipLeftWhitespace($pos);
        if ($skipTokenType === \T_WHITESPACE) {
            return $pos;
        }

        if (!$tokens[$pos]->is($skipTokenType)) {
            // Shouldn't happen. The skip token MUST be there
            throw new \Exception('Encountered unexpected token');
        }
        $pos--;

        return $this->skipLeftWhitespace($pos);
    }

    /** @param int|string|(int|string)[] $skipTokenType */
    public function skipRight(int $pos, $skipTokenType): int {
        $tokens = $this->tokens;

        $pos = $this->skipRightWhitespace($pos);
        if ($skipTokenType === \T_WHITESPACE) {
            return $pos;
        }

        if (!$tokens[$pos]->is($skipTokenType)) {
            // Shouldn't happen. The skip token MUST be there
            throw new \Exception('Encountered unexpected token');
        }
        $pos++;

        return $this->skipRightWhitespace($pos);
    }

    /**
     * Return first non-whitespace token position smaller or equal to passed position.
     *
     * @param int $pos Token position
     * @return int Non-whitespace token position
     */
    public function skipLeftWhitespace(int $pos): int {
        $tokens = $this->tokens;
        for (; $pos >= 0; $pos--) {
            if (!$tokens[$pos]->isIgnorable()) {
                break;
            }
        }
        return $pos;
    }

    /**
     * Return first non-whitespace position greater or equal to passed position.
     *
     * @param int $pos Token position
     * @return int Non-whitespace token position
     */
    public function skipRightWhitespace(int $pos): int {
        $tokens = $this->tokens;
        for ($count = \count($tokens); $pos < $count; $pos++) {
            if (!$tokens[$pos]->isIgnorable()) {
                break;
            }
        }
        return $pos;
    }

    /** @param int|string|(int|string)[] $findTokenType */
    public function findRight(int $pos, $findTokenType): int {
        $tokens = $this->tokens;
        for ($count = \count($tokens); $pos < $count; $pos++) {
            if ($tokens[$pos]->is($findTokenType)) {
                return $pos;
            }
        }
        return -1;
    }

    /**
     * Whether the given position range contains a certain token type.
     *
     * @param int $startPos Starting position (inclusive)
     * @param int $endPos Ending position (exclusive)
     * @param int|string $tokenType Token type to look for
     * @return bool Whether the token occurs in the given range
     */
    public function haveTokenInRange(int $startPos, int $endPos, $tokenType): bool {
        $tokens = $this->tokens;
        for ($pos = $startPos; $pos < $endPos; $pos++) {
            if ($tokens[$pos]->is($tokenType)) {
                return true;
            }
        }
        return false;
    }

    public function haveTagInRange(int $startPos, int $endPos): bool {
        return $this->haveTokenInRange($startPos, $endPos, \T_OPEN_TAG)
            || $this->haveTokenInRange($startPos, $endPos, \T_CLOSE_TAG);
    }

    /**
     * Get indentation before token position.
     *
     * @param int $pos Token position
     *
     * @return int Indentation depth (in spaces)
     */
    public function getIndentationBefore(int $pos): int {
        return $this->indentMap[$pos];
    }

    /**
     * Get the code corresponding to a token offset range, optionally adjusted for indentation.
     *
     * @param int $from Token start position (inclusive)
     * @param int $to Token end position (exclusive)
     * @param int $indent By how much the code should be indented (can be negative as well)
     *
     * @return string Code corresponding to token range, adjusted for indentation
     */
    public function getTokenCode(int $from, int $to, int $indent): string {
        $tokens = $this->tokens;
        $result = '';
        for ($pos = $from; $pos < $to; $pos++) {
            $token = $tokens[$pos];
            $id = $token->id;
            $text = $token->text;
            if ($id === \T_CONSTANT_ENCAPSED_STRING || $id === \T_ENCAPSED_AND_WHITESPACE) {
                $result .= $text;
            } else {
                // TODO Handle non-space indentation
                if ($indent < 0) {
                    $result .= str_replace("\n" . str_repeat(" ", -$indent), "\n", $text);
                } elseif ($indent > 0) {
                    $result .= str_replace("\n", "\n" . str_repeat(" ", $indent), $text);
                } else {
                    $result .= $text;
                }
            }
        }
        return $result;
    }

    /**
     * Precalculate the indentation at every token position.
     *
     * @return int[] Token position to indentation map
     */
    private function calcIndentMap(): array {
        $indentMap = [];
        $indent = 0;
        foreach ($this->tokens as $i => $token) {
            $indentMap[] = $indent;

            if ($token->id === \T_WHITESPACE) {
                $content = $token->text;
                $newlinePos = \strrpos($content, "\n");
                if (false !== $newlinePos) {
                    $indent = \strlen($content) - $newlinePos - 1;
                } elseif ($i === 1 && $this->tokens[0]->id === \T_OPEN_TAG &&
                          $this->tokens[0]->text[\strlen($this->tokens[0]->text) - 1] === "\n") {
                    // Special case: Newline at the end of opening tag followed by whitespace.
                    $indent = \strlen($content);
                }
            }
        }

        // Add a sentinel for one past end of the file
        $indentMap[] = $indent;

        return $indentMap;
    }
}
Builder/Property.php000064400000007711151520657540010507 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\ComplexType;

class Property implements PhpParser\Builder {
    protected string $name;

    protected int $flags = 0;

    protected ?Node\Expr $default = null;
    /** @var array<string, mixed> */
    protected array $attributes = [];
    /** @var null|Identifier|Name|ComplexType */
    protected ?Node $type = null;
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates a property builder.
     *
     * @param string $name Name of the property
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Makes the property public.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePublic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);

        return $this;
    }

    /**
     * Makes the property protected.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeProtected() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);

        return $this;
    }

    /**
     * Makes the property private.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePrivate() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);

        return $this;
    }

    /**
     * Makes the property static.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeStatic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);

        return $this;
    }

    /**
     * Makes the property readonly.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeReadonly() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);

        return $this;
    }

    /**
     * Sets default value for the property.
     *
     * @param mixed $value Default value to use
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDefault($value) {
        $this->default = BuilderHelpers::normalizeValue($value);

        return $this;
    }

    /**
     * Sets doc comment for the property.
     *
     * @param PhpParser\Comment\Doc|string $docComment Doc comment to set
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDocComment($docComment) {
        $this->attributes = [
            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
        ];

        return $this;
    }

    /**
     * Sets the property type for PHP 7.4+.
     *
     * @param string|Name|Identifier|ComplexType $type
     *
     * @return $this
     */
    public function setType($type) {
        $this->type = BuilderHelpers::normalizeType($type);

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built class node.
     *
     * @return Stmt\Property The built property node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\Property(
            $this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,
            [
                new Node\PropertyItem($this->name, $this->default)
            ],
            $this->attributes,
            $this->type,
            $this->attributeGroups
        );
    }
}
Builder/TraitUseAdaptation.php000064400000010252151520657540012422 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser\Builder;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class TraitUseAdaptation implements Builder {
    private const TYPE_UNDEFINED  = 0;
    private const TYPE_ALIAS      = 1;
    private const TYPE_PRECEDENCE = 2;

    protected int $type;
    protected ?Node\Name $trait;
    protected Node\Identifier $method;
    protected ?int $modifier = null;
    protected ?Node\Identifier $alias = null;
    /** @var Node\Name[] */
    protected array $insteadof = [];

    /**
     * Creates a trait use adaptation builder.
     *
     * @param Node\Name|string|null $trait Name of adapted trait
     * @param Node\Identifier|string $method Name of adapted method
     */
    public function __construct($trait, $method) {
        $this->type = self::TYPE_UNDEFINED;

        $this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait);
        $this->method = BuilderHelpers::normalizeIdentifier($method);
    }

    /**
     * Sets alias of method.
     *
     * @param Node\Identifier|string $alias Alias for adapted method
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function as($alias) {
        if ($this->type === self::TYPE_UNDEFINED) {
            $this->type = self::TYPE_ALIAS;
        }

        if ($this->type !== self::TYPE_ALIAS) {
            throw new \LogicException('Cannot set alias for not alias adaptation buider');
        }

        $this->alias = BuilderHelpers::normalizeIdentifier($alias);
        return $this;
    }

    /**
     * Sets adapted method public.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePublic() {
        $this->setModifier(Modifiers::PUBLIC);
        return $this;
    }

    /**
     * Sets adapted method protected.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeProtected() {
        $this->setModifier(Modifiers::PROTECTED);
        return $this;
    }

    /**
     * Sets adapted method private.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePrivate() {
        $this->setModifier(Modifiers::PRIVATE);
        return $this;
    }

    /**
     * Adds overwritten traits.
     *
     * @param Node\Name|string ...$traits Traits for overwrite
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function insteadof(...$traits) {
        if ($this->type === self::TYPE_UNDEFINED) {
            if (is_null($this->trait)) {
                throw new \LogicException('Precedence adaptation must have trait');
            }

            $this->type = self::TYPE_PRECEDENCE;
        }

        if ($this->type !== self::TYPE_PRECEDENCE) {
            throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider');
        }

        foreach ($traits as $trait) {
            $this->insteadof[] = BuilderHelpers::normalizeName($trait);
        }

        return $this;
    }

    protected function setModifier(int $modifier): void {
        if ($this->type === self::TYPE_UNDEFINED) {
            $this->type = self::TYPE_ALIAS;
        }

        if ($this->type !== self::TYPE_ALIAS) {
            throw new \LogicException('Cannot set access modifier for not alias adaptation buider');
        }

        if (is_null($this->modifier)) {
            $this->modifier = $modifier;
        } else {
            throw new \LogicException('Multiple access type modifiers are not allowed');
        }
    }

    /**
     * Returns the built node.
     *
     * @return Node The built node
     */
    public function getNode(): Node {
        switch ($this->type) {
            case self::TYPE_ALIAS:
                return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias);
            case self::TYPE_PRECEDENCE:
                return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof);
            default:
                throw new \LogicException('Type of adaptation is not defined');
        }
    }
}
Builder/FunctionLike.php000064400000003416151520657540011253 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser\BuilderHelpers;
use PhpParser\Node;

abstract class FunctionLike extends Declaration {
    protected bool $returnByRef = false;
    /** @var Node\Param[] */
    protected array $params = [];

    /** @var Node\Identifier|Node\Name|Node\ComplexType|null */
    protected ?Node $returnType = null;

    /**
     * Make the function return by reference.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeReturnByRef() {
        $this->returnByRef = true;

        return $this;
    }

    /**
     * Adds a parameter.
     *
     * @param Node\Param|Param $param The parameter to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addParam($param) {
        $param = BuilderHelpers::normalizeNode($param);

        if (!$param instanceof Node\Param) {
            throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
        }

        $this->params[] = $param;

        return $this;
    }

    /**
     * Adds multiple parameters.
     *
     * @param (Node\Param|Param)[] $params The parameters to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addParams(array $params) {
        foreach ($params as $param) {
            $this->addParam($param);
        }

        return $this;
    }

    /**
     * Sets the return type for PHP 7.
     *
     * @param string|Node\Name|Node\Identifier|Node\ComplexType $type
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setReturnType($type) {
        $this->returnType = BuilderHelpers::normalizeType($type);

        return $this;
    }
}
Builder/Interface_.php000064400000005104151520657540010714 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;

class Interface_ extends Declaration {
    protected string $name;
    /** @var list<Name> */
    protected array $extends = [];
    /** @var list<Stmt\ClassConst> */
    protected array $constants = [];
    /** @var list<Stmt\ClassMethod> */
    protected array $methods = [];
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates an interface builder.
     *
     * @param string $name Name of the interface
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Extends one or more interfaces.
     *
     * @param Name|string ...$interfaces Names of interfaces to extend
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function extend(...$interfaces) {
        foreach ($interfaces as $interface) {
            $this->extends[] = BuilderHelpers::normalizeName($interface);
        }

        return $this;
    }

    /**
     * Adds a statement.
     *
     * @param Stmt|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $stmt = BuilderHelpers::normalizeNode($stmt);

        if ($stmt instanceof Stmt\ClassConst) {
            $this->constants[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassMethod) {
            // we erase all statements in the body of an interface method
            $stmt->stmts = null;
            $this->methods[] = $stmt;
        } else {
            throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
        }

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built interface node.
     *
     * @return Stmt\Interface_ The built interface node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\Interface_($this->name, [
            'extends' => $this->extends,
            'stmts' => array_merge($this->constants, $this->methods),
            'attrGroups' => $this->attributeGroups,
        ], $this->attributes);
    }
}
Builder/Trait_.php000064400000004464151520657540010107 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class Trait_ extends Declaration {
    protected string $name;
    /** @var list<Stmt\TraitUse> */
    protected array $uses = [];
    /** @var list<Stmt\ClassConst> */
    protected array $constants = [];
    /** @var list<Stmt\Property> */
    protected array $properties = [];
    /** @var list<Stmt\ClassMethod> */
    protected array $methods = [];
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates an interface builder.
     *
     * @param string $name Name of the interface
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Adds a statement.
     *
     * @param Stmt|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $stmt = BuilderHelpers::normalizeNode($stmt);

        if ($stmt instanceof Stmt\Property) {
            $this->properties[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassMethod) {
            $this->methods[] = $stmt;
        } elseif ($stmt instanceof Stmt\TraitUse) {
            $this->uses[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassConst) {
            $this->constants[] = $stmt;
        } else {
            throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
        }

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built trait node.
     *
     * @return Stmt\Trait_ The built interface node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\Trait_(
            $this->name, [
                'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
                'attrGroups' => $this->attributeGroups,
            ], $this->attributes
        );
    }
}
Builder/Declaration.php000064400000002355151520657540011107 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;

abstract class Declaration implements PhpParser\Builder {
    /** @var array<string, mixed> */
    protected array $attributes = [];

    /**
     * Adds a statement.
     *
     * @param PhpParser\Node\Stmt|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    abstract public function addStmt($stmt);

    /**
     * Adds multiple statements.
     *
     * @param (PhpParser\Node\Stmt|PhpParser\Builder)[] $stmts The statements to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmts(array $stmts) {
        foreach ($stmts as $stmt) {
            $this->addStmt($stmt);
        }

        return $this;
    }

    /**
     * Sets doc comment for the declaration.
     *
     * @param PhpParser\Comment\Doc|string $docComment Doc comment to set
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDocComment($docComment) {
        $this->attributes['comments'] = [
            BuilderHelpers::normalizeDocComment($docComment)
        ];

        return $this;
    }
}
Builder/TraitUse.php000064400000003166151520657540010423 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser\Builder;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class TraitUse implements Builder {
    /** @var Node\Name[] */
    protected array $traits = [];
    /** @var Stmt\TraitUseAdaptation[] */
    protected array $adaptations = [];

    /**
     * Creates a trait use builder.
     *
     * @param Node\Name|string ...$traits Names of used traits
     */
    public function __construct(...$traits) {
        foreach ($traits as $trait) {
            $this->and($trait);
        }
    }

    /**
     * Adds used trait.
     *
     * @param Node\Name|string $trait Trait name
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function and($trait) {
        $this->traits[] = BuilderHelpers::normalizeName($trait);
        return $this;
    }

    /**
     * Adds trait adaptation.
     *
     * @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function with($adaptation) {
        $adaptation = BuilderHelpers::normalizeNode($adaptation);

        if (!$adaptation instanceof Stmt\TraitUseAdaptation) {
            throw new \LogicException('Adaptation must have type TraitUseAdaptation');
        }

        $this->adaptations[] = $adaptation;
        return $this;
    }

    /**
     * Returns the built node.
     *
     * @return Node The built node
     */
    public function getNode(): Node {
        return new Stmt\TraitUse($this->traits, $this->adaptations);
    }
}
Builder/Enum_.php000064400000006272151520657540007727 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;

class Enum_ extends Declaration {
    protected string $name;
    protected ?Identifier $scalarType = null;
    /** @var list<Name> */
    protected array $implements = [];
    /** @var list<Stmt\TraitUse> */
    protected array $uses = [];
    /** @var list<Stmt\EnumCase> */
    protected array $enumCases = [];
    /** @var list<Stmt\ClassConst> */
    protected array $constants = [];
    /** @var list<Stmt\ClassMethod> */
    protected array $methods = [];
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates an enum builder.
     *
     * @param string $name Name of the enum
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Sets the scalar type.
     *
     * @param string|Identifier $scalarType
     *
     * @return $this
     */
    public function setScalarType($scalarType) {
        $this->scalarType = BuilderHelpers::normalizeType($scalarType);

        return $this;
    }

    /**
     * Implements one or more interfaces.
     *
     * @param Name|string ...$interfaces Names of interfaces to implement
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function implement(...$interfaces) {
        foreach ($interfaces as $interface) {
            $this->implements[] = BuilderHelpers::normalizeName($interface);
        }

        return $this;
    }

    /**
     * Adds a statement.
     *
     * @param Stmt|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $stmt = BuilderHelpers::normalizeNode($stmt);

        if ($stmt instanceof Stmt\EnumCase) {
            $this->enumCases[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassMethod) {
            $this->methods[] = $stmt;
        } elseif ($stmt instanceof Stmt\TraitUse) {
            $this->uses[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassConst) {
            $this->constants[] = $stmt;
        } else {
            throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
        }

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built class node.
     *
     * @return Stmt\Enum_ The built enum node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\Enum_($this->name, [
            'scalarType' => $this->scalarType,
            'implements' => $this->implements,
            'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods),
            'attrGroups' => $this->attributeGroups,
        ], $this->attributes);
    }
}
Builder/Class_.php000064400000010113151520657540010055 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;

class Class_ extends Declaration {
    protected string $name;
    protected ?Name $extends = null;
    /** @var list<Name> */
    protected array $implements = [];
    protected int $flags = 0;
    /** @var list<Stmt\TraitUse> */
    protected array $uses = [];
    /** @var list<Stmt\ClassConst> */
    protected array $constants = [];
    /** @var list<Stmt\Property> */
    protected array $properties = [];
    /** @var list<Stmt\ClassMethod> */
    protected array $methods = [];
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates a class builder.
     *
     * @param string $name Name of the class
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Extends a class.
     *
     * @param Name|string $class Name of class to extend
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function extend($class) {
        $this->extends = BuilderHelpers::normalizeName($class);

        return $this;
    }

    /**
     * Implements one or more interfaces.
     *
     * @param Name|string ...$interfaces Names of interfaces to implement
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function implement(...$interfaces) {
        foreach ($interfaces as $interface) {
            $this->implements[] = BuilderHelpers::normalizeName($interface);
        }

        return $this;
    }

    /**
     * Makes the class abstract.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeAbstract() {
        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::ABSTRACT);

        return $this;
    }

    /**
     * Makes the class final.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeFinal() {
        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL);

        return $this;
    }

    /**
     * Makes the class readonly.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeReadonly() {
        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::READONLY);

        return $this;
    }

    /**
     * Adds a statement.
     *
     * @param Stmt|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $stmt = BuilderHelpers::normalizeNode($stmt);

        if ($stmt instanceof Stmt\Property) {
            $this->properties[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassMethod) {
            $this->methods[] = $stmt;
        } elseif ($stmt instanceof Stmt\TraitUse) {
            $this->uses[] = $stmt;
        } elseif ($stmt instanceof Stmt\ClassConst) {
            $this->constants[] = $stmt;
        } else {
            throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
        }

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built class node.
     *
     * @return Stmt\Class_ The built class node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\Class_($this->name, [
            'flags' => $this->flags,
            'extends' => $this->extends,
            'implements' => $this->implements,
            'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
            'attrGroups' => $this->attributeGroups,
        ], $this->attributes);
    }
}
Builder/ClassConst.php000064400000007417151520657540010742 0ustar00<?php

declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Const_;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;

class ClassConst implements PhpParser\Builder {
    protected int $flags = 0;
    /** @var array<string, mixed> */
    protected array $attributes = [];
    /** @var list<Const_> */
    protected array $constants = [];

    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];
    /** @var Identifier|Node\Name|Node\ComplexType|null */
    protected ?Node $type = null;

    /**
     * Creates a class constant builder
     *
     * @param string|Identifier $name Name
     * @param Node\Expr|bool|null|int|float|string|array $value Value
     */
    public function __construct($name, $value) {
        $this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
    }

    /**
     * Add another constant to const group
     *
     * @param string|Identifier $name Name
     * @param Node\Expr|bool|null|int|float|string|array $value Value
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addConst($name, $value) {
        $this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value));

        return $this;
    }

    /**
     * Makes the constant public.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePublic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);

        return $this;
    }

    /**
     * Makes the constant protected.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeProtected() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);

        return $this;
    }

    /**
     * Makes the constant private.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePrivate() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);

        return $this;
    }

    /**
     * Makes the constant final.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeFinal() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);

        return $this;
    }

    /**
     * Sets doc comment for the constant.
     *
     * @param PhpParser\Comment\Doc|string $docComment Doc comment to set
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDocComment($docComment) {
        $this->attributes = [
            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
        ];

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Sets the constant type.
     *
     * @param string|Node\Name|Identifier|Node\ComplexType $type
     *
     * @return $this
     */
    public function setType($type) {
        $this->type = BuilderHelpers::normalizeType($type);

        return $this;
    }

    /**
     * Returns the built class node.
     *
     * @return Stmt\ClassConst The built constant node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\ClassConst(
            $this->constants,
            $this->flags,
            $this->attributes,
            $this->attributeGroups,
            $this->type
        );
    }
}
Builder/Param.php000064400000007410151520657540007717 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;

class Param implements PhpParser\Builder {
    protected string $name;
    protected ?Node\Expr $default = null;
    /** @var Node\Identifier|Node\Name|Node\ComplexType|null */
    protected ?Node $type = null;
    protected bool $byRef = false;
    protected int $flags = 0;
    protected bool $variadic = false;
    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates a parameter builder.
     *
     * @param string $name Name of the parameter
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Sets default value for the parameter.
     *
     * @param mixed $value Default value to use
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDefault($value) {
        $this->default = BuilderHelpers::normalizeValue($value);

        return $this;
    }

    /**
     * Sets type for the parameter.
     *
     * @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setType($type) {
        $this->type = BuilderHelpers::normalizeType($type);
        if ($this->type == 'void') {
            throw new \LogicException('Parameter type cannot be void');
        }

        return $this;
    }

    /**
     * Make the parameter accept the value by reference.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeByRef() {
        $this->byRef = true;

        return $this;
    }

    /**
     * Make the parameter variadic
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeVariadic() {
        $this->variadic = true;

        return $this;
    }

    /**
     * Makes the (promoted) parameter public.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePublic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);

        return $this;
    }

    /**
     * Makes the (promoted) parameter protected.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeProtected() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);

        return $this;
    }

    /**
     * Makes the (promoted) parameter private.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePrivate() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);

        return $this;
    }

    /**
     * Makes the (promoted) parameter readonly.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeReadonly() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built parameter node.
     *
     * @return Node\Param The built parameter node
     */
    public function getNode(): Node {
        return new Node\Param(
            new Node\Expr\Variable($this->name),
            $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups
        );
    }
}
Builder/EnumCase.php000064400000003757151520657540010371 0ustar00<?php

declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;

class EnumCase implements PhpParser\Builder {
    /** @var Identifier|string */
    protected $name;
    /** @var ?Node\Expr */
    protected ?Node\Expr $value = null;
    /** @var array<string, mixed> */
    protected array $attributes = [];

    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates an enum case builder.
     *
     * @param string|Identifier $name Name
     */
    public function __construct($name) {
        $this->name = $name;
    }

    /**
     * Sets the value.
     *
     * @param Node\Expr|string|int $value
     *
     * @return $this
     */
    public function setValue($value) {
        $this->value = BuilderHelpers::normalizeValue($value);

        return $this;
    }

    /**
     * Sets doc comment for the constant.
     *
     * @param PhpParser\Comment\Doc|string $docComment Doc comment to set
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function setDocComment($docComment) {
        $this->attributes = [
            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
        ];

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built enum case node.
     *
     * @return Stmt\EnumCase The built constant node
     */
    public function getNode(): PhpParser\Node {
        return new Stmt\EnumCase(
            $this->name,
            $this->value,
            $this->attributeGroups,
            $this->attributes
        );
    }
}
Builder/Function_.php000064400000003233151520657540010602 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class Function_ extends FunctionLike {
    protected string $name;
    /** @var list<Stmt> */
    protected array $stmts = [];

    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates a function builder.
     *
     * @param string $name Name of the function
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Adds a statement.
     *
     * @param Node|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built function node.
     *
     * @return Stmt\Function_ The built function node
     */
    public function getNode(): Node {
        return new Stmt\Function_($this->name, [
            'byRef'      => $this->returnByRef,
            'params'     => $this->params,
            'returnType' => $this->returnType,
            'stmts'      => $this->stmts,
            'attrGroups' => $this->attributeGroups,
        ], $this->attributes);
    }
}
Builder/Namespace_.php000064400000002061151520657540010707 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class Namespace_ extends Declaration {
    private ?Node\Name $name;
    /** @var Stmt[] */
    private array $stmts = [];

    /**
     * Creates a namespace builder.
     *
     * @param Node\Name|string|null $name Name of the namespace
     */
    public function __construct($name) {
        $this->name = null !== $name ? BuilderHelpers::normalizeName($name) : null;
    }

    /**
     * Adds a statement.
     *
     * @param Node|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);

        return $this;
    }

    /**
     * Returns the built node.
     *
     * @return Stmt\Namespace_ The built node
     */
    public function getNode(): Node {
        return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes);
    }
}
Builder/Method.php000064400000007254151520657540010105 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser;
use PhpParser\BuilderHelpers;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class Method extends FunctionLike {
    protected string $name;

    protected int $flags = 0;

    /** @var list<Stmt>|null */
    protected ?array $stmts = [];

    /** @var list<Node\AttributeGroup> */
    protected array $attributeGroups = [];

    /**
     * Creates a method builder.
     *
     * @param string $name Name of the method
     */
    public function __construct(string $name) {
        $this->name = $name;
    }

    /**
     * Makes the method public.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePublic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);

        return $this;
    }

    /**
     * Makes the method protected.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeProtected() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);

        return $this;
    }

    /**
     * Makes the method private.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makePrivate() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);

        return $this;
    }

    /**
     * Makes the method static.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeStatic() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);

        return $this;
    }

    /**
     * Makes the method abstract.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeAbstract() {
        if (!empty($this->stmts)) {
            throw new \LogicException('Cannot make method with statements abstract');
        }

        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
        $this->stmts = null; // abstract methods don't have statements

        return $this;
    }

    /**
     * Makes the method final.
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function makeFinal() {
        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);

        return $this;
    }

    /**
     * Adds a statement.
     *
     * @param Node|PhpParser\Builder $stmt The statement to add
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addStmt($stmt) {
        if (null === $this->stmts) {
            throw new \LogicException('Cannot add statements to an abstract method');
        }

        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);

        return $this;
    }

    /**
     * Adds an attribute group.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function addAttribute($attribute) {
        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);

        return $this;
    }

    /**
     * Returns the built method node.
     *
     * @return Stmt\ClassMethod The built method node
     */
    public function getNode(): Node {
        return new Stmt\ClassMethod($this->name, [
            'flags'      => $this->flags,
            'byRef'      => $this->returnByRef,
            'params'     => $this->params,
            'returnType' => $this->returnType,
            'stmts'      => $this->stmts,
            'attrGroups' => $this->attributeGroups,
        ], $this->attributes);
    }
}
Builder/Use_.php000064400000002375151520657540007557 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Builder;

use PhpParser\Builder;
use PhpParser\BuilderHelpers;
use PhpParser\Node;
use PhpParser\Node\Stmt;

class Use_ implements Builder {
    protected Node\Name $name;
    /** @var Stmt\Use_::TYPE_* */
    protected int $type;
    protected ?string $alias = null;

    /**
     * Creates a name use (alias) builder.
     *
     * @param Node\Name|string $name Name of the entity (namespace, class, function, constant) to alias
     * @param Stmt\Use_::TYPE_* $type One of the Stmt\Use_::TYPE_* constants
     */
    public function __construct($name, int $type) {
        $this->name = BuilderHelpers::normalizeName($name);
        $this->type = $type;
    }

    /**
     * Sets alias for used name.
     *
     * @param string $alias Alias to use (last component of full name by default)
     *
     * @return $this The builder instance (for fluid interface)
     */
    public function as(string $alias) {
        $this->alias = $alias;
        return $this;
    }

    /**
     * Returns the built node.
     *
     * @return Stmt\Use_ The built node
     */
    public function getNode(): Node {
        return new Stmt\Use_([
            new Node\UseItem($this->name, $this->alias)
        ], $this->type);
    }
}
Error.php000064400000011412151520657540006357 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

class Error extends \RuntimeException {
    protected string $rawMessage;
    /** @var array<string, mixed> */
    protected array $attributes;

    /**
     * Creates an Exception signifying a parse error.
     *
     * @param string $message Error message
     * @param array<string, mixed> $attributes Attributes of node/token where error occurred
     */
    public function __construct(string $message, array $attributes = []) {
        $this->rawMessage = $message;
        $this->attributes = $attributes;
        $this->updateMessage();
    }

    /**
     * Gets the error message
     *
     * @return string Error message
     */
    public function getRawMessage(): string {
        return $this->rawMessage;
    }

    /**
     * Gets the line the error starts in.
     *
     * @return int Error start line
     */
    public function getStartLine(): int {
        return $this->attributes['startLine'] ?? -1;
    }

    /**
     * Gets the line the error ends in.
     *
     * @return int Error end line
     */
    public function getEndLine(): int {
        return $this->attributes['endLine'] ?? -1;
    }

    /**
     * Gets the attributes of the node/token the error occurred at.
     *
     * @return array<string, mixed>
     */
    public function getAttributes(): array {
        return $this->attributes;
    }

    /**
     * Sets the attributes of the node/token the error occurred at.
     *
     * @param array<string, mixed> $attributes
     */
    public function setAttributes(array $attributes): void {
        $this->attributes = $attributes;
        $this->updateMessage();
    }

    /**
     * Sets the line of the PHP file the error occurred in.
     *
     * @param string $message Error message
     */
    public function setRawMessage(string $message): void {
        $this->rawMessage = $message;
        $this->updateMessage();
    }

    /**
     * Sets the line the error starts in.
     *
     * @param int $line Error start line
     */
    public function setStartLine(int $line): void {
        $this->attributes['startLine'] = $line;
        $this->updateMessage();
    }

    /**
     * Returns whether the error has start and end column information.
     *
     * For column information enable the startFilePos and endFilePos in the lexer options.
     */
    public function hasColumnInfo(): bool {
        return isset($this->attributes['startFilePos'], $this->attributes['endFilePos']);
    }

    /**
     * Gets the start column (1-based) into the line where the error started.
     *
     * @param string $code Source code of the file
     */
    public function getStartColumn(string $code): int {
        if (!$this->hasColumnInfo()) {
            throw new \RuntimeException('Error does not have column information');
        }

        return $this->toColumn($code, $this->attributes['startFilePos']);
    }

    /**
     * Gets the end column (1-based) into the line where the error ended.
     *
     * @param string $code Source code of the file
     */
    public function getEndColumn(string $code): int {
        if (!$this->hasColumnInfo()) {
            throw new \RuntimeException('Error does not have column information');
        }

        return $this->toColumn($code, $this->attributes['endFilePos']);
    }

    /**
     * Formats message including line and column information.
     *
     * @param string $code Source code associated with the error, for calculation of the columns
     *
     * @return string Formatted message
     */
    public function getMessageWithColumnInfo(string $code): string {
        return sprintf(
            '%s from %d:%d to %d:%d', $this->getRawMessage(),
            $this->getStartLine(), $this->getStartColumn($code),
            $this->getEndLine(), $this->getEndColumn($code)
        );
    }

    /**
     * Converts a file offset into a column.
     *
     * @param string $code Source code that $pos indexes into
     * @param int $pos 0-based position in $code
     *
     * @return int 1-based column (relative to start of line)
     */
    private function toColumn(string $code, int $pos): int {
        if ($pos > strlen($code)) {
            throw new \RuntimeException('Invalid position information');
        }

        $lineStartPos = strrpos($code, "\n", $pos - strlen($code));
        if (false === $lineStartPos) {
            $lineStartPos = -1;
        }

        return $pos - $lineStartPos;
    }

    /**
     * Updates the exception message after a change to rawMessage or rawLine.
     */
    protected function updateMessage(): void {
        $this->message = $this->rawMessage;

        if (-1 === $this->getStartLine()) {
            $this->message .= ' on unknown line';
        } else {
            $this->message .= ' on line ' . $this->getStartLine();
        }
    }
}
ErrorHandler.php000064400000000454151520657540007661 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface ErrorHandler {
    /**
     * Handle an error generated during lexing, parsing or some other operation.
     *
     * @param Error $error The error that needs to be handled
     */
    public function handleError(Error $error): void;
}
Node.php000064400000007577151520657540006174 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface Node {
    /**
     * Gets the type of the node.
     *
     * @return string Type of the node
     */
    public function getType(): string;

    /**
     * Gets the names of the sub nodes.
     *
     * @return string[] Names of sub nodes
     */
    public function getSubNodeNames(): array;

    /**
     * Gets line the node started in (alias of getStartLine).
     *
     * @return int Start line (or -1 if not available)
     *
     * @deprecated Use getStartLine() instead
     */
    public function getLine(): int;

    /**
     * Gets line the node started in.
     *
     * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default).
     *
     * @return int Start line (or -1 if not available)
     */
    public function getStartLine(): int;

    /**
     * Gets the line the node ended in.
     *
     * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default).
     *
     * @return int End line (or -1 if not available)
     */
    public function getEndLine(): int;

    /**
     * Gets the token offset of the first token that is part of this node.
     *
     * The offset is an index into the array returned by Lexer::getTokens().
     *
     * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int Token start position (or -1 if not available)
     */
    public function getStartTokenPos(): int;

    /**
     * Gets the token offset of the last token that is part of this node.
     *
     * The offset is an index into the array returned by Lexer::getTokens().
     *
     * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int Token end position (or -1 if not available)
     */
    public function getEndTokenPos(): int;

    /**
     * Gets the file offset of the first character that is part of this node.
     *
     * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int File start position (or -1 if not available)
     */
    public function getStartFilePos(): int;

    /**
     * Gets the file offset of the last character that is part of this node.
     *
     * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int File end position (or -1 if not available)
     */
    public function getEndFilePos(): int;

    /**
     * Gets all comments directly preceding this node.
     *
     * The comments are also available through the "comments" attribute.
     *
     * @return Comment[]
     */
    public function getComments(): array;

    /**
     * Gets the doc comment of the node.
     *
     * @return null|Comment\Doc Doc comment object or null
     */
    public function getDocComment(): ?Comment\Doc;

    /**
     * Sets the doc comment of the node.
     *
     * This will either replace an existing doc comment or add it to the comments array.
     *
     * @param Comment\Doc $docComment Doc comment to set
     */
    public function setDocComment(Comment\Doc $docComment): void;

    /**
     * Sets an attribute on a node.
     *
     * @param mixed $value
     */
    public function setAttribute(string $key, $value): void;

    /**
     * Returns whether an attribute exists.
     */
    public function hasAttribute(string $key): bool;

    /**
     * Returns the value of an attribute.
     *
     * @param mixed $default
     *
     * @return mixed
     */
    public function getAttribute(string $key, $default = null);

    /**
     * Returns all the attributes of this node.
     *
     * @return array<string, mixed>
     */
    public function getAttributes(): array;

    /**
     * Replaces all the attributes of this node.
     *
     * @param array<string, mixed> $attributes
     */
    public function setAttributes(array $attributes): void;
}
Token.php000064400000000747151520657540006357 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

/**
 * A PHP token. On PHP 8.0 this extends from PhpToken.
 */
class Token extends Internal\TokenPolyfill {
    /** Get (exclusive) zero-based end position of the token. */
    public function getEndPos(): int {
        return $this->pos + \strlen($this->text);
    }

    /** Get 1-based end line number of the token. */
    public function getEndLine(): int {
        return $this->line + \substr_count($this->text, "\n");
    }
}
Modifiers.php000064400000004232151520657540007211 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

/**
 * Modifiers used (as a bit mask) by various flags subnodes, for example on classes, functions,
 * properties and constants.
 */
final class Modifiers {
    public const PUBLIC    =  1;
    public const PROTECTED =  2;
    public const PRIVATE   =  4;
    public const STATIC    =  8;
    public const ABSTRACT  = 16;
    public const FINAL     = 32;
    public const READONLY  = 64;

    public const VISIBILITY_MASK = 1 | 2 | 4;

    /**
     * @internal
     */
    public static function verifyClassModifier(int $a, int $b): void {
        if ($a & Modifiers::ABSTRACT && $b & Modifiers::ABSTRACT) {
            throw new Error('Multiple abstract modifiers are not allowed');
        }

        if ($a & Modifiers::FINAL && $b & Modifiers::FINAL) {
            throw new Error('Multiple final modifiers are not allowed');
        }

        if ($a & Modifiers::READONLY && $b & Modifiers::READONLY) {
            throw new Error('Multiple readonly modifiers are not allowed');
        }

        if ($a & 48 && $b & 48) {
            throw new Error('Cannot use the final modifier on an abstract class');
        }
    }

    /**
     * @internal
     */
    public static function verifyModifier(int $a, int $b): void {
        if ($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK) {
            throw new Error('Multiple access type modifiers are not allowed');
        }

        if ($a & Modifiers::ABSTRACT && $b & Modifiers::ABSTRACT) {
            throw new Error('Multiple abstract modifiers are not allowed');
        }

        if ($a & Modifiers::STATIC && $b & Modifiers::STATIC) {
            throw new Error('Multiple static modifiers are not allowed');
        }

        if ($a & Modifiers::FINAL && $b & Modifiers::FINAL) {
            throw new Error('Multiple final modifiers are not allowed');
        }

        if ($a & Modifiers::READONLY && $b & Modifiers::READONLY) {
            throw new Error('Multiple readonly modifiers are not allowed');
        }

        if ($a & 48 && $b & 48) {
            throw new Error('Cannot use the final modifier on an abstract class member');
        }
    }
}
ErrorHandler/Throwing.php000064400000000560151520657540011460 0ustar00<?php declare(strict_types=1);

namespace PhpParser\ErrorHandler;

use PhpParser\Error;
use PhpParser\ErrorHandler;

/**
 * Error handler that handles all errors by throwing them.
 *
 * This is the default strategy used by all components.
 */
class Throwing implements ErrorHandler {
    public function handleError(Error $error): void {
        throw $error;
    }
}
ErrorHandler/Collecting.php000064400000001545151520657540011746 0ustar00<?php declare(strict_types=1);

namespace PhpParser\ErrorHandler;

use PhpParser\Error;
use PhpParser\ErrorHandler;

/**
 * Error handler that collects all errors into an array.
 *
 * This allows graceful handling of errors.
 */
class Collecting implements ErrorHandler {
    /** @var Error[] Collected errors */
    private array $errors = [];

    public function handleError(Error $error): void {
        $this->errors[] = $error;
    }

    /**
     * Get collected errors.
     *
     * @return Error[]
     */
    public function getErrors(): array {
        return $this->errors;
    }

    /**
     * Check whether there are any errors.
     */
    public function hasErrors(): bool {
        return !empty($this->errors);
    }

    /**
     * Reset/clear collected errors.
     */
    public function clearErrors(): void {
        $this->errors = [];
    }
}
JsonDecoder.php000064400000006700151520657540007471 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

class JsonDecoder {
    /** @var \ReflectionClass<Node>[] Node type to reflection class map */
    private array $reflectionClassCache;

    /** @return mixed */
    public function decode(string $json) {
        $value = json_decode($json, true);
        if (json_last_error()) {
            throw new \RuntimeException('JSON decoding error: ' . json_last_error_msg());
        }

        return $this->decodeRecursive($value);
    }

    /**
     * @param mixed $value
     * @return mixed
     */
    private function decodeRecursive($value) {
        if (\is_array($value)) {
            if (isset($value['nodeType'])) {
                if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') {
                    return $this->decodeComment($value);
                }
                return $this->decodeNode($value);
            }
            return $this->decodeArray($value);
        }
        return $value;
    }

    private function decodeArray(array $array): array {
        $decodedArray = [];
        foreach ($array as $key => $value) {
            $decodedArray[$key] = $this->decodeRecursive($value);
        }
        return $decodedArray;
    }

    private function decodeNode(array $value): Node {
        $nodeType = $value['nodeType'];
        if (!\is_string($nodeType)) {
            throw new \RuntimeException('Node type must be a string');
        }

        $reflectionClass = $this->reflectionClassFromNodeType($nodeType);
        $node = $reflectionClass->newInstanceWithoutConstructor();

        if (isset($value['attributes'])) {
            if (!\is_array($value['attributes'])) {
                throw new \RuntimeException('Attributes must be an array');
            }

            $node->setAttributes($this->decodeArray($value['attributes']));
        }

        foreach ($value as $name => $subNode) {
            if ($name === 'nodeType' || $name === 'attributes') {
                continue;
            }

            $node->$name = $this->decodeRecursive($subNode);
        }

        return $node;
    }

    private function decodeComment(array $value): Comment {
        $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\Doc::class;
        if (!isset($value['text'])) {
            throw new \RuntimeException('Comment must have text');
        }

        return new $className(
            $value['text'],
            $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,
            $value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1
        );
    }

    /** @return \ReflectionClass<Node> */
    private function reflectionClassFromNodeType(string $nodeType): \ReflectionClass {
        if (!isset($this->reflectionClassCache[$nodeType])) {
            $className = $this->classNameFromNodeType($nodeType);
            $this->reflectionClassCache[$nodeType] = new \ReflectionClass($className);
        }
        return $this->reflectionClassCache[$nodeType];
    }

    /** @return class-string<Node> */
    private function classNameFromNodeType(string $nodeType): string {
        $className = 'PhpParser\\Node\\' . strtr($nodeType, '_', '\\');
        if (class_exists($className)) {
            return $className;
        }

        $className .= '_';
        if (class_exists($className)) {
            return $className;
        }

        throw new \RuntimeException("Unknown node type \"$nodeType\"");
    }
}
PhpVersion.php000064400000010735151520657540007372 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

/**
 * A PHP version, representing only the major and minor version components.
 */
class PhpVersion {
    /** @var int Version ID in PHP_VERSION_ID format */
    public int $id;

    /** @var int[] Minimum versions for builtin types */
    private const BUILTIN_TYPE_VERSIONS = [
        'array'    => 50100,
        'callable' => 50400,
        'bool'     => 70000,
        'int'      => 70000,
        'float'    => 70000,
        'string'   => 70000,
        'iterable' => 70100,
        'void'     => 70100,
        'object'   => 70200,
        'null'     => 80000,
        'false'    => 80000,
        'mixed'    => 80000,
        'never'    => 80100,
        'true'     => 80200,
    ];

    private function __construct(int $id) {
        $this->id = $id;
    }

    /**
     * Create a PhpVersion object from major and minor version components.
     */
    public static function fromComponents(int $major, int $minor): self {
        return new self($major * 10000 + $minor * 100);
    }

    /**
     * Get the newest PHP version supported by this library. Support for this version may be partial,
     * if it is still under development.
     */
    public static function getNewestSupported(): self {
        return self::fromComponents(8, 3);
    }

    /**
     * Get the host PHP version, that is the PHP version we're currently running on.
     */
    public static function getHostVersion(): self {
        return self::fromComponents(\PHP_MAJOR_VERSION, \PHP_MINOR_VERSION);
    }

    /**
     * Parse the version from a string like "8.1".
     */
    public static function fromString(string $version): self {
        if (!preg_match('/^(\d+)\.(\d+)/', $version, $matches)) {
            throw new \LogicException("Invalid PHP version \"$version\"");
        }
        return self::fromComponents((int) $matches[1], (int) $matches[2]);
    }

    /**
     * Check whether two versions are the same.
     */
    public function equals(PhpVersion $other): bool {
        return $this->id === $other->id;
    }

    /**
     * Check whether this version is greater than or equal to the argument.
     */
    public function newerOrEqual(PhpVersion $other): bool {
        return $this->id >= $other->id;
    }

    /**
     * Check whether this version is older than the argument.
     */
    public function older(PhpVersion $other): bool {
        return $this->id < $other->id;
    }

    /**
     * Check whether this is the host PHP version.
     */
    public function isHostVersion(): bool {
        return $this->equals(self::getHostVersion());
    }

    /**
     * Check whether this PHP version supports the given builtin type. Type name must be lowercase.
     */
    public function supportsBuiltinType(string $type): bool {
        $minVersion = self::BUILTIN_TYPE_VERSIONS[$type] ?? null;
        return $minVersion !== null && $this->id >= $minVersion;
    }

    /**
     * Whether this version supports [] array literals.
     */
    public function supportsShortArraySyntax(): bool {
        return $this->id >= 50400;
    }

    /**
     * Whether this version supports [] for destructuring.
     */
    public function supportsShortArrayDestructuring(): bool {
        return $this->id >= 70100;
    }

    /**
     * Whether this version supports flexible heredoc/nowdoc.
     */
    public function supportsFlexibleHeredoc(): bool {
        return $this->id >= 70300;
    }

    /**
     * Whether this version supports trailing commas in parameter lists.
     */
    public function supportsTrailingCommaInParamList(): bool {
        return $this->id >= 80000;
    }

    /**
     * Whether this version allows "$var =& new Obj".
     */
    public function allowsAssignNewByReference(): bool {
        return $this->id < 70000;
    }

    /**
     * Whether this version allows invalid octals like "08".
     */
    public function allowsInvalidOctals(): bool {
        return $this->id < 70000;
    }

    /**
     * Whether this version allows DEL (\x7f) to occur in identifiers.
     */
    public function allowsDelInIdentifiers(): bool {
        return $this->id < 70100;
    }

    /**
     * Whether this version supports yield in expression context without parentheses.
     */
    public function supportsYieldWithoutParentheses(): bool {
        return $this->id >= 70000;
    }

    /**
     * Whether this version supports unicode escape sequences in strings.
     */
    public function supportsUnicodeEscapes(): bool {
        return $this->id >= 70000;
    }
}
Lexer/TokenEmulator/NullsafeTokenEmulator.php000064400000004352151520657540015426 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;
use PhpParser\Token;

final class NullsafeTokenEmulator extends TokenEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(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
        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
            $token = $tokens[$i];
            if ($token->text === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1]->id === \T_OBJECT_OPERATOR) {
                array_splice($tokens, $i, 2, [
                    new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos),
                ]);
                $c--;
                continue;
            }

            // Handle ?-> inside encapsed string.
            if ($token->id === \T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1])
                && $tokens[$i - 1]->id === \T_VARIABLE
                && preg_match('/^\?->([a-zA-Z_\x80-\xff][a-zA-Z0-9_\x80-\xff]*)/', $token->text, $matches)
            ) {
                $replacement = [
                    new Token(\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos),
                    new Token(\T_STRING, $matches[1], $token->line, $token->pos + 3),
                ];
                $matchLen = \strlen($matches[0]);
                if ($matchLen !== \strlen($token->text)) {
                    $replacement[] = new Token(
                        \T_ENCAPSED_AND_WHITESPACE,
                        \substr($token->text, $matchLen),
                        $token->line, $token->pos + $matchLen
                    );
                }
                array_splice($tokens, $i, 1, $replacement);
                $c += \count($replacement) - 1;
                continue;
            }
        }

        return $tokens;
    }

    public function reverseEmulate(string $code, array $tokens): array {
        // ?-> was not valid code previously, don't bother.
        return $tokens;
    }
}
Lexer/TokenEmulator/ExplicitOctalEmulator.php000064400000003041151520657540015412 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;
use PhpParser\Token;

class ExplicitOctalEmulator extends TokenEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(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) {
            $token = $tokens[$i];
            if ($token->id == \T_LNUMBER && $token->text === '0' &&
                isset($tokens[$i + 1]) && $tokens[$i + 1]->id == \T_STRING &&
                preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1]->text)
            ) {
                $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1]->text);
                array_splice($tokens, $i, 2, [
                    new Token($tokenKind, '0' . $tokens[$i + 1]->text, $token->line, $token->pos),
                ]);
                $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;
    }
}
Lexer/TokenEmulator/ReverseEmulator.php000064400000001765151520657540014274 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;

/**
 * Reverses emulation direction of the inner emulator.
 */
final class ReverseEmulator extends TokenEmulator {
    /** @var TokenEmulator Inner emulator */
    private TokenEmulator $emulator;

    public function __construct(TokenEmulator $emulator) {
        $this->emulator = $emulator;
    }

    public function getPhpVersion(): PhpVersion {
        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;
    }
}
Lexer/TokenEmulator/MatchTokenEmulator.php000064400000000646151520657540014713 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;

final class MatchTokenEmulator extends KeywordEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(8, 0);
    }

    public function getKeywordString(): string {
        return 'match';
    }

    public function getKeywordToken(): int {
        return \T_MATCH;
    }
}
Lexer/TokenEmulator/ReadonlyTokenEmulator.php000064400000001611151520657540015425 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;

final class ReadonlyTokenEmulator extends KeywordEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(8, 1);
    }

    public function getKeywordString(): string {
        return 'readonly';
    }

    public function getKeywordToken(): int {
        return \T_READONLY;
    }

    protected function isKeywordContext(array $tokens, int $pos): bool {
        if (!parent::isKeywordContext($tokens, $pos)) {
            return false;
        }
        // Support "function readonly("
        return !(isset($tokens[$pos + 1]) &&
                 ($tokens[$pos + 1]->text === '(' ||
                  ($tokens[$pos + 1]->id === \T_WHITESPACE &&
                   isset($tokens[$pos + 2]) &&
                   $tokens[$pos + 2]->text === '(')));
    }
}
Lexer/TokenEmulator/AttributeEmulator.php000064400000002701151520657540014613 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;
use PhpParser\Token;

final class AttributeEmulator extends TokenEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(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.
        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {
            $token = $tokens[$i];
            if ($token->text === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '[') {
                array_splice($tokens, $i, 2, [
                    new Token(\T_ATTRIBUTE, '#[', $token->line, $token->pos),
                ]);
                $c--;
                continue;
            }
        }

        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;
    }
}
Lexer/TokenEmulator/EnumTokenEmulator.php000064400000001275151520657540014562 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;

final class EnumTokenEmulator extends KeywordEmulator {
    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(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]->id === \T_WHITESPACE
            && $tokens[$pos + 2]->id === \T_STRING;
    }
}
Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php000064400000001720151520657540017134 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;

/*
 * In PHP 8.1, "readonly(" was special cased in the lexer in order to support functions with
 * name readonly. In PHP 8.2, this may conflict with readonly properties having a DNF type. For
 * this reason, PHP 8.2 instead treats this as T_READONLY and then handles it specially in the
 * parser. This emulator only exists to handle this special case, which is skipped by the
 * PHP 8.1 ReadonlyTokenEmulator.
 */
class ReadonlyFunctionTokenEmulator extends KeywordEmulator {
    public function getKeywordString(): string {
        return 'readonly';
    }

    public function getKeywordToken(): int {
        return \T_READONLY;
    }

    public function getPhpVersion(): PhpVersion {
        return PhpVersion::fromComponents(8, 2);
    }

    public function reverseEmulate(string $code, array $tokens): array {
        // Don't bother
        return $tokens;
    }
}
Lexer/TokenEmulator/KeywordEmulator.php000064400000003341151520657540014275 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\Token;

abstract class KeywordEmulator extends TokenEmulator {
    abstract public function getKeywordString(): string;
    abstract public function getKeywordToken(): int;

    public function isEmulationNeeded(string $code): bool {
        return strpos(strtolower($code), $this->getKeywordString()) !== false;
    }

    /** @param Token[] $tokens */
    protected function isKeywordContext(array $tokens, int $pos): bool {
        $previousNonSpaceToken = $this->getPreviousNonSpaceToken($tokens, $pos);
        return $previousNonSpaceToken === null || $previousNonSpaceToken->id !== \T_OBJECT_OPERATOR;
    }

    public function emulate(string $code, array $tokens): array {
        $keywordString = $this->getKeywordString();
        foreach ($tokens as $i => $token) {
            if ($token->id === T_STRING && strtolower($token->text) === $keywordString
                    && $this->isKeywordContext($tokens, $i)) {
                $token->id = $this->getKeywordToken();
            }
        }

        return $tokens;
    }

    /** @param Token[] $tokens */
    private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token {
        for ($i = $start - 1; $i >= 0; --$i) {
            if ($tokens[$i]->id === T_WHITESPACE) {
                continue;
            }

            return $tokens[$i];
        }

        return null;
    }

    public function reverseEmulate(string $code, array $tokens): array {
        $keywordToken = $this->getKeywordToken();
        foreach ($tokens as $token) {
            if ($token->id === $keywordToken) {
                $token->id = \T_STRING;
            }
        }

        return $tokens;
    }
}
Lexer/TokenEmulator/TokenEmulator.php000064400000001463151520657540013734 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer\TokenEmulator;

use PhpParser\PhpVersion;
use PhpParser\Token;

/** @internal */
abstract class TokenEmulator {
    abstract public function getPhpVersion(): PhpVersion;

    abstract public function isEmulationNeeded(string $code): bool;

    /**
     * @param Token[] $tokens Original tokens
     * @return Token[] Modified Tokens
     */
    abstract public function emulate(string $code, array $tokens): array;

    /**
     * @param Token[] $tokens Original tokens
     * @return Token[] Modified Tokens
     */
    abstract public function reverseEmulate(string $code, array $tokens): array;

    /** @param array{int, string, string}[] $patches */
    public function preprocessCode(string $code, array &$patches): string {
        return $code;
    }
}
Lexer/Emulative.php000064400000020252151520657540010302 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Lexer;

use PhpParser\Error;
use PhpParser\ErrorHandler;
use PhpParser\Lexer;
use PhpParser\Lexer\TokenEmulator\AttributeEmulator;
use PhpParser\Lexer\TokenEmulator\EnumTokenEmulator;
use PhpParser\Lexer\TokenEmulator\CoaleseEqualTokenEmulator;
use PhpParser\Lexer\TokenEmulator\ExplicitOctalEmulator;
use PhpParser\Lexer\TokenEmulator\FlexibleDocStringEmulator;
use PhpParser\Lexer\TokenEmulator\FnTokenEmulator;
use PhpParser\Lexer\TokenEmulator\MatchTokenEmulator;
use PhpParser\Lexer\TokenEmulator\NullsafeTokenEmulator;
use PhpParser\Lexer\TokenEmulator\NumericLiteralSeparatorEmulator;
use PhpParser\Lexer\TokenEmulator\ReadonlyFunctionTokenEmulator;
use PhpParser\Lexer\TokenEmulator\ReadonlyTokenEmulator;
use PhpParser\Lexer\TokenEmulator\ReverseEmulator;
use PhpParser\Lexer\TokenEmulator\TokenEmulator;
use PhpParser\PhpVersion;
use PhpParser\Token;

class Emulative extends Lexer {
    /** @var array{int, string, string}[] Patches used to reverse changes introduced in the code */
    private array $patches = [];

    /** @var list<TokenEmulator> */
    private array $emulators = [];

    private PhpVersion $targetPhpVersion;

    private PhpVersion $hostPhpVersion;

    /**
     * @param PhpVersion|null $phpVersion PHP version to emulate. Defaults to newest supported.
     */
    public function __construct(?PhpVersion $phpVersion = null) {
        $this->targetPhpVersion = $phpVersion ?? PhpVersion::getNewestSupported();
        $this->hostPhpVersion = PhpVersion::getHostVersion();

        $emulators = [
            new MatchTokenEmulator(),
            new NullsafeTokenEmulator(),
            new AttributeEmulator(),
            new EnumTokenEmulator(),
            new ReadonlyTokenEmulator(),
            new ExplicitOctalEmulator(),
            new ReadonlyFunctionTokenEmulator(),
        ];

        // Collect emulators that are relevant for the PHP version we're running
        // and the PHP version we're targeting for emulation.
        foreach ($emulators as $emulator) {
            $emulatorPhpVersion = $emulator->getPhpVersion();
            if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) {
                $this->emulators[] = $emulator;
            } elseif ($this->isReverseEmulationNeeded($emulatorPhpVersion)) {
                $this->emulators[] = new ReverseEmulator($emulator);
            }
        }
    }

    public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array {
        $emulators = array_filter($this->emulators, function ($emulator) use ($code) {
            return $emulator->isEmulationNeeded($code);
        });

        if (empty($emulators)) {
            // Nothing to emulate, yay
            return parent::tokenize($code, $errorHandler);
        }

        if ($errorHandler === null) {
            $errorHandler = new ErrorHandler\Throwing();
        }

        $this->patches = [];
        foreach ($emulators as $emulator) {
            $code = $emulator->preprocessCode($code, $this->patches);
        }

        $collector = new ErrorHandler\Collecting();
        $tokens = parent::tokenize($code, $collector);
        $this->sortPatches();
        $tokens = $this->fixupTokens($tokens);

        $errors = $collector->getErrors();
        if (!empty($errors)) {
            $this->fixupErrors($errors);
            foreach ($errors as $error) {
                $errorHandler->handleError($error);
            }
        }

        foreach ($emulators as $emulator) {
            $tokens = $emulator->emulate($code, $tokens);
        }

        return $tokens;
    }

    private function isForwardEmulationNeeded(PhpVersion $emulatorPhpVersion): bool {
        return $this->hostPhpVersion->older($emulatorPhpVersion)
            && $this->targetPhpVersion->newerOrEqual($emulatorPhpVersion);
    }

    private function isReverseEmulationNeeded(PhpVersion $emulatorPhpVersion): bool {
        return $this->hostPhpVersion->newerOrEqual($emulatorPhpVersion)
            && $this->targetPhpVersion->older($emulatorPhpVersion);
    }

    private function sortPatches(): void {
        // Patches may be contributed by different emulators.
        // Make sure they are sorted by increasing patch position.
        usort($this->patches, function ($p1, $p2) {
            return $p1[0] <=> $p2[0];
        });
    }

    /**
     * @param list<Token> $tokens
     * @return list<Token>
     */
    private function fixupTokens(array $tokens): array {
        if (\count($this->patches) === 0) {
            return $tokens;
        }

        // Load first patch
        $patchIdx = 0;
        list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx];

        // We use a manual loop over the tokens, because we modify the array on the fly
        $posDelta = 0;
        $lineDelta = 0;
        for ($i = 0, $c = \count($tokens); $i < $c; $i++) {
            $token = $tokens[$i];
            $pos = $token->pos;
            $token->pos += $posDelta;
            $token->line += $lineDelta;
            $localPosDelta = 0;
            $len = \strlen($token->text);
            while ($patchPos >= $pos && $patchPos < $pos + $len) {
                $patchTextLen = \strlen($patchText);
                if ($patchType === 'remove') {
                    if ($patchPos === $pos && $patchTextLen === $len) {
                        // Remove token entirely
                        array_splice($tokens, $i, 1, []);
                        $i--;
                        $c--;
                    } else {
                        // Remove from token string
                        $token->text = substr_replace(
                            $token->text, '', $patchPos - $pos + $localPosDelta, $patchTextLen
                        );
                        $localPosDelta -= $patchTextLen;
                    }
                    $lineDelta -= \substr_count($patchText, "\n");
                } elseif ($patchType === 'add') {
                    // Insert into the token string
                    $token->text = substr_replace(
                        $token->text, $patchText, $patchPos - $pos + $localPosDelta, 0
                    );
                    $localPosDelta += $patchTextLen;
                    $lineDelta += \substr_count($patchText, "\n");
                } elseif ($patchType === 'replace') {
                    // Replace inside the token string
                    $token->text = substr_replace(
                        $token->text, $patchText, $patchPos - $pos + $localPosDelta, $patchTextLen
                    );
                } else {
                    assert(false);
                }

                // Fetch the next patch
                $patchIdx++;
                if ($patchIdx >= \count($this->patches)) {
                    // No more patches. However, we still need to adjust position.
                    $patchPos = \PHP_INT_MAX;
                    break;
                }

                list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx];
            }

            $posDelta += $localPosDelta;
        }
        return $tokens;
    }

    /**
     * Fixup line and position information in errors.
     *
     * @param Error[] $errors
     */
    private function fixupErrors(array $errors): void {
        foreach ($errors as $error) {
            $attrs = $error->getAttributes();

            $posDelta = 0;
            $lineDelta = 0;
            foreach ($this->patches as $patch) {
                list($patchPos, $patchType, $patchText) = $patch;
                if ($patchPos >= $attrs['startFilePos']) {
                    // No longer relevant
                    break;
                }

                if ($patchType === 'add') {
                    $posDelta += strlen($patchText);
                    $lineDelta += substr_count($patchText, "\n");
                } elseif ($patchType === 'remove') {
                    $posDelta -= strlen($patchText);
                    $lineDelta -= substr_count($patchText, "\n");
                }
            }

            $attrs['startFilePos'] += $posDelta;
            $attrs['endFilePos'] += $posDelta;
            $attrs['startLine'] += $lineDelta;
            $attrs['endLine'] += $lineDelta;
            $error->setAttributes($attrs);
        }
    }
}
NodeAbstract.php000064400000012205151520657540007640 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

abstract class NodeAbstract implements Node, \JsonSerializable {
    /** @var array<string, mixed> Attributes */
    protected array $attributes;

    /**
     * Creates a Node.
     *
     * @param array<string, mixed> $attributes Array of attributes
     */
    public function __construct(array $attributes = []) {
        $this->attributes = $attributes;
    }

    /**
     * Gets line the node started in (alias of getStartLine).
     *
     * @return int Start line (or -1 if not available)
     */
    public function getLine(): int {
        return $this->attributes['startLine'] ?? -1;
    }

    /**
     * Gets line the node started in.
     *
     * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default).
     *
     * @return int Start line (or -1 if not available)
     */
    public function getStartLine(): int {
        return $this->attributes['startLine'] ?? -1;
    }

    /**
     * Gets the line the node ended in.
     *
     * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default).
     *
     * @return int End line (or -1 if not available)
     */
    public function getEndLine(): int {
        return $this->attributes['endLine'] ?? -1;
    }

    /**
     * Gets the token offset of the first token that is part of this node.
     *
     * The offset is an index into the array returned by Lexer::getTokens().
     *
     * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int Token start position (or -1 if not available)
     */
    public function getStartTokenPos(): int {
        return $this->attributes['startTokenPos'] ?? -1;
    }

    /**
     * Gets the token offset of the last token that is part of this node.
     *
     * The offset is an index into the array returned by Lexer::getTokens().
     *
     * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int Token end position (or -1 if not available)
     */
    public function getEndTokenPos(): int {
        return $this->attributes['endTokenPos'] ?? -1;
    }

    /**
     * Gets the file offset of the first character that is part of this node.
     *
     * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int File start position (or -1 if not available)
     */
    public function getStartFilePos(): int {
        return $this->attributes['startFilePos'] ?? -1;
    }

    /**
     * Gets the file offset of the last character that is part of this node.
     *
     * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default).
     *
     * @return int File end position (or -1 if not available)
     */
    public function getEndFilePos(): int {
        return $this->attributes['endFilePos'] ?? -1;
    }

    /**
     * Gets all comments directly preceding this node.
     *
     * The comments are also available through the "comments" attribute.
     *
     * @return Comment[]
     */
    public function getComments(): array {
        return $this->attributes['comments'] ?? [];
    }

    /**
     * Gets the doc comment of the node.
     *
     * @return null|Comment\Doc Doc comment object or null
     */
    public function getDocComment(): ?Comment\Doc {
        $comments = $this->getComments();
        for ($i = count($comments) - 1; $i >= 0; $i--) {
            $comment = $comments[$i];
            if ($comment instanceof Comment\Doc) {
                return $comment;
            }
        }

        return null;
    }

    /**
     * Sets the doc comment of the node.
     *
     * This will either replace an existing doc comment or add it to the comments array.
     *
     * @param Comment\Doc $docComment Doc comment to set
     */
    public function setDocComment(Comment\Doc $docComment): void {
        $comments = $this->getComments();
        for ($i = count($comments) - 1; $i >= 0; $i--) {
            if ($comments[$i] instanceof Comment\Doc) {
                // Replace existing doc comment.
                $comments[$i] = $docComment;
                $this->setAttribute('comments', $comments);
                return;
            }
        }

        // Append new doc comment.
        $comments[] = $docComment;
        $this->setAttribute('comments', $comments);
    }

    public function setAttribute(string $key, $value): void {
        $this->attributes[$key] = $value;
    }

    public function hasAttribute(string $key): bool {
        return array_key_exists($key, $this->attributes);
    }

    public function getAttribute(string $key, $default = null) {
        if (array_key_exists($key, $this->attributes)) {
            return $this->attributes[$key];
        }

        return $default;
    }

    public function getAttributes(): array {
        return $this->attributes;
    }

    public function setAttributes(array $attributes): void {
        $this->attributes = $attributes;
    }

    /**
     * @return array<string, mixed>
     */
    public function jsonSerialize(): array {
        return ['nodeType' => $this->getType()] + get_object_vars($this);
    }
}
compatibility_tokens.php000064400000004400151520657540011521 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

if (!\function_exists('PhpParser\defineCompatibilityTokens')) {
    function defineCompatibilityTokens(): void {
        $compatTokens = [
            // PHP 8.0
            'T_NAME_QUALIFIED',
            'T_NAME_FULLY_QUALIFIED',
            'T_NAME_RELATIVE',
            'T_MATCH',
            'T_NULLSAFE_OBJECT_OPERATOR',
            'T_ATTRIBUTE',
            // PHP 8.1
            'T_ENUM',
            'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG',
            'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG',
            'T_READONLY',
        ];

        // PHP-Parser might be used together with another library that also emulates some or all
        // of these tokens. Perform a sanity-check that all already defined tokens have been
        // assigned a unique ID.
        $usedTokenIds = [];
        foreach ($compatTokens as $token) {
            if (\defined($token)) {
                $tokenId = \constant($token);
                if (!\is_int($tokenId)) {
                    throw new \Error(sprintf(
                        'Token %s has ID of type %s, should be int. ' .
                        'You may be using a library with broken token emulation',
                        $token, \gettype($tokenId)
                    ));
                }
                $clashingToken = $usedTokenIds[$tokenId] ?? null;
                if ($clashingToken !== null) {
                    throw new \Error(sprintf(
                        'Token %s has same ID as token %s, ' .
                        'you may be using a library with broken token emulation',
                        $token, $clashingToken
                    ));
                }
                $usedTokenIds[$tokenId] = $token;
            }
        }

        // Now define any tokens that have not yet been emulated. Try to assign IDs from -1
        // downwards, but skip any IDs that may already be in use.
        $newTokenId = -1;
        foreach ($compatTokens as $token) {
            if (!\defined($token)) {
                while (isset($usedTokenIds[$newTokenId])) {
                    $newTokenId--;
                }
                \define($token, $newTokenId);
                $newTokenId--;
            }
        }
    }

    defineCompatibilityTokens();
}
Lexer.php000064400000010416151520657540006350 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

require __DIR__ . '/compatibility_tokens.php';

class Lexer {
    /**
     * Tokenize the provided source code.
     *
     * The token array is in the same format as provided by the PhpToken::tokenize() method in
     * PHP 8.0. The tokens are instances of PhpParser\Token, to abstract over a polyfill
     * implementation in earlier PHP version.
     *
     * The token array is terminated by a sentinel token with token ID 0.
     * The token array does not discard any tokens (i.e. whitespace and comments are included).
     * The token position attributes are against this token array.
     *
     * @param string $code The source code to tokenize.
     * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to
     *                                        ErrorHandler\Throwing.
     * @return Token[] Tokens
     */
    public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array {
        if (null === $errorHandler) {
            $errorHandler = new ErrorHandler\Throwing();
        }

        $scream = ini_set('xdebug.scream', '0');

        $tokens = @Token::tokenize($code);
        $this->postprocessTokens($tokens, $errorHandler);

        if (false !== $scream) {
            ini_set('xdebug.scream', $scream);
        }

        return $tokens;
    }

    private function handleInvalidCharacter(Token $token, ErrorHandler $errorHandler): void {
        $chr = $token->text;
        if ($chr === "\0") {
            // PHP cuts error message after null byte, so need special case
            $errorMsg = 'Unexpected null byte';
        } else {
            $errorMsg = sprintf(
                'Unexpected character "%s" (ASCII %d)', $chr, ord($chr)
            );
        }

        $errorHandler->handleError(new Error($errorMsg, [
            'startLine' => $token->line,
            'endLine' => $token->line,
            'startFilePos' => $token->pos,
            'endFilePos' => $token->pos,
        ]));
    }

    private function isUnterminatedComment(Token $token): bool {
        return $token->is([\T_COMMENT, \T_DOC_COMMENT])
            && substr($token->text, 0, 2) === '/*'
            && substr($token->text, -2) !== '*/';
    }

    /**
     * @param list<Token> $tokens
     */
    protected function postprocessTokens(array &$tokens, ErrorHandler $errorHandler): void {
        // This function reports errors (bad characters and unterminated comments) in the token
        // array, and performs certain canonicalizations:
        //  * Use PHP 8.1 T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG and
        //    T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG tokens used to disambiguate intersection types.
        //  * Add a sentinel token with ID 0.

        $numTokens = \count($tokens);
        if ($numTokens === 0) {
            // Empty input edge case: Just add the sentinel token.
            $tokens[] = new Token(0, "\0", 1, 0);
            return;
        }

        for ($i = 0; $i < $numTokens; $i++) {
            $token = $tokens[$i];
            if ($token->id === \T_BAD_CHARACTER) {
                $this->handleInvalidCharacter($token, $errorHandler);
            }

            if ($token->id === \ord('&')) {
                $next = $i + 1;
                while (isset($tokens[$next]) && $tokens[$next]->id === \T_WHITESPACE) {
                    $next++;
                }
                $followedByVarOrVarArg = isset($tokens[$next]) &&
                    $tokens[$next]->is([\T_VARIABLE, \T_ELLIPSIS]);
                $token->id = $followedByVarOrVarArg
                    ? \T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG
                    : \T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG;
            }
        }

        // Check for unterminated comment
        $lastToken = $tokens[$numTokens - 1];
        if ($this->isUnterminatedComment($lastToken)) {
            $errorHandler->handleError(new Error('Unterminated comment', [
                'startLine' => $lastToken->line,
                'endLine' => $lastToken->getEndLine(),
                'startFilePos' => $lastToken->pos,
                'endFilePos' => $lastToken->getEndPos(),
            ]));
        }

        // Add sentinel token.
        $tokens[] = new Token(0, "\0", $lastToken->getEndLine(), $lastToken->getEndPos());
    }
}
Parser/Php7.php000064400000536615151520657540007361 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Parser;

use PhpParser\Error;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;

/* This is an automatically GENERATED file, which should not be manually edited.
 * Instead edit one of the following:
 *  * the grammar file grammar/php.y
 *  * the skeleton file grammar/parser.template
 *  * the preprocessing script grammar/rebuildParsers.php
 */
class Php7 extends \PhpParser\ParserAbstract
{
    public const YYERRTOK = 256;
    public const T_THROW = 257;
    public const T_INCLUDE = 258;
    public const T_INCLUDE_ONCE = 259;
    public const T_EVAL = 260;
    public const T_REQUIRE = 261;
    public const T_REQUIRE_ONCE = 262;
    public const T_LOGICAL_OR = 263;
    public const T_LOGICAL_XOR = 264;
    public const T_LOGICAL_AND = 265;
    public const T_PRINT = 266;
    public const T_YIELD = 267;
    public const T_DOUBLE_ARROW = 268;
    public const T_YIELD_FROM = 269;
    public const T_PLUS_EQUAL = 270;
    public const T_MINUS_EQUAL = 271;
    public const T_MUL_EQUAL = 272;
    public const T_DIV_EQUAL = 273;
    public const T_CONCAT_EQUAL = 274;
    public const T_MOD_EQUAL = 275;
    public const T_AND_EQUAL = 276;
    public const T_OR_EQUAL = 277;
    public const T_XOR_EQUAL = 278;
    public const T_SL_EQUAL = 279;
    public const T_SR_EQUAL = 280;
    public const T_POW_EQUAL = 281;
    public const T_COALESCE_EQUAL = 282;
    public const T_COALESCE = 283;
    public const T_BOOLEAN_OR = 284;
    public const T_BOOLEAN_AND = 285;
    public const T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG = 286;
    public const T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG = 287;
    public const T_IS_EQUAL = 288;
    public const T_IS_NOT_EQUAL = 289;
    public const T_IS_IDENTICAL = 290;
    public const T_IS_NOT_IDENTICAL = 291;
    public const T_SPACESHIP = 292;
    public const T_IS_SMALLER_OR_EQUAL = 293;
    public const T_IS_GREATER_OR_EQUAL = 294;
    public const T_SL = 295;
    public const T_SR = 296;
    public const T_INSTANCEOF = 297;
    public const T_INC = 298;
    public const T_DEC = 299;
    public const T_INT_CAST = 300;
    public const T_DOUBLE_CAST = 301;
    public const T_STRING_CAST = 302;
    public const T_ARRAY_CAST = 303;
    public const T_OBJECT_CAST = 304;
    public const T_BOOL_CAST = 305;
    public const T_UNSET_CAST = 306;
    public const T_POW = 307;
    public const T_NEW = 308;
    public const T_CLONE = 309;
    public const T_EXIT = 310;
    public const T_IF = 311;
    public const T_ELSEIF = 312;
    public const T_ELSE = 313;
    public const T_ENDIF = 314;
    public const T_LNUMBER = 315;
    public const T_DNUMBER = 316;
    public const T_STRING = 317;
    public const T_STRING_VARNAME = 318;
    public const T_VARIABLE = 319;
    public const T_NUM_STRING = 320;
    public const T_INLINE_HTML = 321;
    public const T_ENCAPSED_AND_WHITESPACE = 322;
    public const T_CONSTANT_ENCAPSED_STRING = 323;
    public const T_ECHO = 324;
    public const T_DO = 325;
    public const T_WHILE = 326;
    public const T_ENDWHILE = 327;
    public const T_FOR = 328;
    public const T_ENDFOR = 329;
    public const T_FOREACH = 330;
    public const T_ENDFOREACH = 331;
    public const T_DECLARE = 332;
    public const T_ENDDECLARE = 333;
    public const T_AS = 334;
    public const T_SWITCH = 335;
    public const T_MATCH = 336;
    public const T_ENDSWITCH = 337;
    public const T_CASE = 338;
    public const T_DEFAULT = 339;
    public const T_BREAK = 340;
    public const T_CONTINUE = 341;
    public const T_GOTO = 342;
    public const T_FUNCTION = 343;
    public const T_FN = 344;
    public const T_CONST = 345;
    public const T_RETURN = 346;
    public const T_TRY = 347;
    public const T_CATCH = 348;
    public const T_FINALLY = 349;
    public const T_USE = 350;
    public const T_INSTEADOF = 351;
    public const T_GLOBAL = 352;
    public const T_STATIC = 353;
    public const T_ABSTRACT = 354;
    public const T_FINAL = 355;
    public const T_PRIVATE = 356;
    public const T_PROTECTED = 357;
    public const T_PUBLIC = 358;
    public const T_READONLY = 359;
    public const T_VAR = 360;
    public const T_UNSET = 361;
    public const T_ISSET = 362;
    public const T_EMPTY = 363;
    public const T_HALT_COMPILER = 364;
    public const T_CLASS = 365;
    public const T_TRAIT = 366;
    public const T_INTERFACE = 367;
    public const T_ENUM = 368;
    public const T_EXTENDS = 369;
    public const T_IMPLEMENTS = 370;
    public const T_OBJECT_OPERATOR = 371;
    public const T_NULLSAFE_OBJECT_OPERATOR = 372;
    public const T_LIST = 373;
    public const T_ARRAY = 374;
    public const T_CALLABLE = 375;
    public const T_CLASS_C = 376;
    public const T_TRAIT_C = 377;
    public const T_METHOD_C = 378;
    public const T_FUNC_C = 379;
    public const T_LINE = 380;
    public const T_FILE = 381;
    public const T_START_HEREDOC = 382;
    public const T_END_HEREDOC = 383;
    public const T_DOLLAR_OPEN_CURLY_BRACES = 384;
    public const T_CURLY_OPEN = 385;
    public const T_PAAMAYIM_NEKUDOTAYIM = 386;
    public const T_NAMESPACE = 387;
    public const T_NS_C = 388;
    public const T_DIR = 389;
    public const T_NS_SEPARATOR = 390;
    public const T_ELLIPSIS = 391;
    public const T_NAME_FULLY_QUALIFIED = 392;
    public const T_NAME_QUALIFIED = 393;
    public const T_NAME_RELATIVE = 394;
    public const T_ATTRIBUTE = 395;

    protected int $tokenToSymbolMapSize = 396;
    protected int $actionTableSize = 1258;
    protected int $gotoTableSize = 567;

    protected int $invalidSymbol = 168;
    protected int $errorSymbol = 1;
    protected int $defaultAction = -32766;
    protected int $unexpectedTokenRule = 32767;

    protected int $YY2TBLSTATE = 435;
    protected int $numNonLeafStates = 739;

    protected array $symbolToName = array(
        "EOF",
        "error",
        "T_THROW",
        "T_INCLUDE",
        "T_INCLUDE_ONCE",
        "T_EVAL",
        "T_REQUIRE",
        "T_REQUIRE_ONCE",
        "','",
        "T_LOGICAL_OR",
        "T_LOGICAL_XOR",
        "T_LOGICAL_AND",
        "T_PRINT",
        "T_YIELD",
        "T_DOUBLE_ARROW",
        "T_YIELD_FROM",
        "'='",
        "T_PLUS_EQUAL",
        "T_MINUS_EQUAL",
        "T_MUL_EQUAL",
        "T_DIV_EQUAL",
        "T_CONCAT_EQUAL",
        "T_MOD_EQUAL",
        "T_AND_EQUAL",
        "T_OR_EQUAL",
        "T_XOR_EQUAL",
        "T_SL_EQUAL",
        "T_SR_EQUAL",
        "T_POW_EQUAL",
        "T_COALESCE_EQUAL",
        "'?'",
        "':'",
        "T_COALESCE",
        "T_BOOLEAN_OR",
        "T_BOOLEAN_AND",
        "'|'",
        "'^'",
        "T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG",
        "T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG",
        "T_IS_EQUAL",
        "T_IS_NOT_EQUAL",
        "T_IS_IDENTICAL",
        "T_IS_NOT_IDENTICAL",
        "T_SPACESHIP",
        "'<'",
        "T_IS_SMALLER_OR_EQUAL",
        "'>'",
        "T_IS_GREATER_OR_EQUAL",
        "T_SL",
        "T_SR",
        "'+'",
        "'-'",
        "'.'",
        "'*'",
        "'/'",
        "'%'",
        "'!'",
        "T_INSTANCEOF",
        "'~'",
        "T_INC",
        "T_DEC",
        "T_INT_CAST",
        "T_DOUBLE_CAST",
        "T_STRING_CAST",
        "T_ARRAY_CAST",
        "T_OBJECT_CAST",
        "T_BOOL_CAST",
        "T_UNSET_CAST",
        "'@'",
        "T_POW",
        "'['",
        "T_NEW",
        "T_CLONE",
        "T_EXIT",
        "T_IF",
        "T_ELSEIF",
        "T_ELSE",
        "T_ENDIF",
        "T_LNUMBER",
        "T_DNUMBER",
        "T_STRING",
        "T_STRING_VARNAME",
        "T_VARIABLE",
        "T_NUM_STRING",
        "T_INLINE_HTML",
        "T_ENCAPSED_AND_WHITESPACE",
        "T_CONSTANT_ENCAPSED_STRING",
        "T_ECHO",
        "T_DO",
        "T_WHILE",
        "T_ENDWHILE",
        "T_FOR",
        "T_ENDFOR",
        "T_FOREACH",
        "T_ENDFOREACH",
        "T_DECLARE",
        "T_ENDDECLARE",
        "T_AS",
        "T_SWITCH",
        "T_MATCH",
        "T_ENDSWITCH",
        "T_CASE",
        "T_DEFAULT",
        "T_BREAK",
        "T_CONTINUE",
        "T_GOTO",
        "T_FUNCTION",
        "T_FN",
        "T_CONST",
        "T_RETURN",
        "T_TRY",
        "T_CATCH",
        "T_FINALLY",
        "T_USE",
        "T_INSTEADOF",
        "T_GLOBAL",
        "T_STATIC",
        "T_ABSTRACT",
        "T_FINAL",
        "T_PRIVATE",
        "T_PROTECTED",
        "T_PUBLIC",
        "T_READONLY",
        "T_VAR",
        "T_UNSET",
        "T_ISSET",
        "T_EMPTY",
        "T_HALT_COMPILER",
        "T_CLASS",
        "T_TRAIT",
        "T_INTERFACE",
        "T_ENUM",
        "T_EXTENDS",
        "T_IMPLEMENTS",
        "T_OBJECT_OPERATOR",
        "T_NULLSAFE_OBJECT_OPERATOR",
        "T_LIST",
        "T_ARRAY",
        "T_CALLABLE",
        "T_CLASS_C",
        "T_TRAIT_C",
        "T_METHOD_C",
        "T_FUNC_C",
        "T_LINE",
        "T_FILE",
        "T_START_HEREDOC",
        "T_END_HEREDOC",
        "T_DOLLAR_OPEN_CURLY_BRACES",
        "T_CURLY_OPEN",
        "T_PAAMAYIM_NEKUDOTAYIM",
        "T_NAMESPACE",
        "T_NS_C",
        "T_DIR",
        "T_NS_SEPARATOR",
        "T_ELLIPSIS",
        "T_NAME_FULLY_QUALIFIED",
        "T_NAME_QUALIFIED",
        "T_NAME_RELATIVE",
        "T_ATTRIBUTE",
        "';'",
        "']'",
        "'('",
        "')'",
        "'{'",
        "'}'",
        "'`'",
        "'\"'",
        "'$'"
    );

    protected array $tokenToSymbol = array(
            0,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,   56,  166,  168,  167,   55,  168,  168,
          161,  162,   53,   50,    8,   51,   52,   54,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,   31,  159,
           44,   16,   46,   30,   68,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,   70,  168,  160,   36,  168,  165,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  163,   35,  164,   58,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,    1,    2,    3,    4,
            5,    6,    7,    9,   10,   11,   12,   13,   14,   15,
           17,   18,   19,   20,   21,   22,   23,   24,   25,   26,
           27,   28,   29,   32,   33,   34,   37,   38,   39,   40,
           41,   42,   43,   45,   47,   48,   49,   57,   59,   60,
           61,   62,   63,   64,   65,   66,   67,   69,   71,   72,
           73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
           83,   84,   85,   86,   87,   88,   89,   90,   91,   92,
           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,
          123,  124,  125,  126,  127,  128,  129,  130,  131,  132,
          133,  134,  135,  136,  137,  138,  139,  140,  141,  142,
          143,  144,  145,  146,  147,  148,  149,  150,  151,  152,
          153,  154,  155,  156,  157,  158
    );

    protected array $action = array(
          133,  134,  135,  582,  136,  137,    0,  751,  752,  753,
          138,   38,-32766,-32766,-32766,  151,-32766,-32766,-32766,-32767,
        -32767,-32767,-32767,  102,  103,  104,  105,  106, 1112, 1113,
         1114, 1111, 1110, 1109, 1115,  745,  744,-32766,-32766,-32766,
        -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,
        -32767, 1245,  837,-32766, 1322,  754,-32766,-32766,-32766,-32766,
         -594,-32766,-32766,-32766,  104,  105,  106, -594, 1306,  265,
          139,  404,  758,  759,  760,  761,  990,-32766,  429,-32766,
        -32766,  -16,-32766,  242, 1027,  815,  762,  763,  764,  765,
          766,  767,  768,  769,  770,  771,  791,  583,  792,  793,
          794,  795,  783,  784,  345,  346,  786,  787,  772,  773,
          774,  776,  777,  778,  356,  818,  819,  820,  821,  822,
          584,  779,  780,  585,  586,-32766,  803,  801,  802,  814,
          798,  799,  835,  826,  587,  588,  797,  589,  590,  591,
          592,  593,  594,  826,  459,  460,  461, 1036,  800,  595,
          596,  941,  140,    2,  133,  134,  135,  582,  136,  137,
         1060,  751,  752,  753,  138,   38, -328, -110, -110, 1326,
          290,   23, -110,-32766,-32766,-32766, 1325,   35, -110, 1112,
         1113, 1114, 1111, 1110, 1109, 1115,  612,-32766,  129,  745,
          744,  107,  108,  109,-32766,  274,-32766,-32766,-32766,-32766,
        -32766,-32766,-32766,  828,  991, -194,  145,  110,  298,  754,
          836,   75,-32766,-32766,-32766, 1351,  142,  326, 1352, -594,
          326, -594,  254,  265,  139,  404,  758,  759,  760,  761,
           82, -272,  429,-32766,  326,-32766,-32766,-32766,-32766,  815,
          762,  763,  764,  765,  766,  767,  768,  769,  770,  771,
          791,  583,  792,  793,  794,  795,  783,  784,  345,  346,
          786,  787,  772,  773,  774,  776,  777,  778,  356,  818,
          819,  820,  821,  822,  584,  779,  780,  585,  586,  830,
          803,  801,  802,  814,  798,  799,  712,  309,  587,  588,
          797,  589,  590,  591,  592,  593,  594,  -78,   83,   84,
           85,  -85,  800,  595,  596,  311,  149,  775,  746,  747,
          748,  749,  750,  725,  751,  752,  753,  788,  789,   37,
         -328,   86,   87,   88,   89,   90,   91,   92,   93,   94,
           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,
          105,  106,  107,  108,  109,  323,  274,  482,-32766,-32766,
        -32766,  -58,-32766,-32766,-32766,  959,  960,  127,  110, -194,
          961,  339,  754,-32766,-32766,-32766,  955,  -85,  291,-32766,
         1088,-32766,-32766,-32766,-32766,-32766,  755,  756,  757,  758,
          759,  760,  761, -193,-32766,  824,-32766,-32766,-32766, -367,
          429, -367,  815,  762,  763,  764,  765,  766,  767,  768,
          769,  770,  771,  791,  813,  792,  793,  794,  795,  783,
          784,  785,  812,  786,  787,  772,  773,  774,  776,  777,
          778,  817,  818,  819,  820,  821,  822,  823,  779,  780,
          781,  782, -548,  803,  801,  802,  814,  798,  799,  340,
          327,  790,  796,  797,  804,  805,  807,  806,  808,  809,
         1033,  391,  606,    7,-32766,  800,  811,  810,   50,   51,
           52,  513,   53,   54,  831, 1240, 1239, 1241,   55,   56,
         -110,   57, 1036,  920, 1090, -110, 1036, -110,  291,  483,
          745,  744,  305,  382,  381, -110, -110, -110, -110, -110,
         -110, -110, -110,  423,  920,  283, -548, -548,  152,  290,
          380,  381, 1245,  715,  467,  468,   58,   59,  370,   21,
          423, -545,   60,  556,   61,  248,  249,   62,   63,   64,
           65,   66,   67,   68,   69, -548,   28,  267,   70,  445,
          514, 1104,  374, -342, 1272, 1273,  515, -193,  835,  154,
          832, -544, 1270,   42,   25,  516,  389,  517,  241,  518,
          920,  519,  298, 1238,  520,  521,  910,  920,  441,   44,
           45,  446,  377,  376,-32766,   46,  522, 1023, 1022, 1021,
         1024,  368,  338,  442, 1278, -545, -545,  910, 1231,  443,
          524,  525,  526,  835, 1245,  835, 1036,  716, 1341, 1236,
         -545,  155,  528,  529,-32766, 1259, 1260, 1261, 1262, 1256,
         1257,  297, -551,  943, -545, -544, -544, 1263, 1258,  290,
         1035, 1240, 1239, 1241,  298,  444, 1036,   71, 1266,  841,
         -544,  321,  322,  326, -153, -153, -153,  920, 1240, 1239,
         1241,  922, -550,  910, -544,  710,  943, -591,-32766, -153,
          910, -153,  357, -153, -591, -153,  862, 1033,  863, 1089,
           36,  251,  922,  737,  156,  375,  710,  717,  862, -585,
          863, -585,   75,  158, -546,  835,  959,  960,  326, 1036,
          -57,  523,  920,-32766,-32766,  362,  896,  955, -110, -110,
         -110,   32,  111,  112,  113,  114,  115,  116,  117,  118,
          119,  120,  121,  122,  123,  745,  744,  656,   26,  835,
         -110, -110,  720,  745,  744, -110,   33,  834,  922,  124,
          910, -110,  710, -153,  125,  922,  675,  676,  130,  710,
        -32766,  150,  407,  131, 1150, 1152,   48,  144, -546, -546,
          378,  379,-32766,  383,  384, -543,   28,  159, 1238,  920,
          160,  298, 1059, -546,   75,-32766,-32766,-32766,  835,-32766,
          326,-32766, 1270,-32766,  -87,  910,-32766, -546,  647,  648,
          161,-32766,-32766,-32766,   -4,  920,  -84,-32766,-32766,  727,
          162,  287,  163,-32766,  420, -302,  -78,  -73,  -72,  -71,
          141,  287,-32766,  -70,  326,  976,  745,  744, 1231,  710,
          299,  300,  -69,  -68,  -67, -298, -591,  -66, -591, -543,
         -543,  -65,  528,  529,  -46, 1259, 1260, 1261, 1262, 1256,
         1257,  -18,   74,  148, -543,  273,  284, 1263, 1258,  126,
         -543,  726,  910,-32766,  729,  919,  147,   73, -543, 1238,
          922,  690,  322,  326,  710,  279,-32766,-32766,-32766,  280,
        -32766,  285,-32766,  286,-32766,  332,  288,-32766,  910,  289,
          292,   49,-32766,-32766,-32766,  293,  274, 1033,-32766,-32766,
          937,  110,  -50,  685,-32766,  420,  146,  691,  826,  701,
          375,  703,  436,-32766, 1353,   20,  561,  296,  645, 1036,
          835,  959,  960, 1119, -543, -543,  523,-32766,  692,  693,
          306,  527,  955, -110, -110, -110,  132,  922,  834, -543,
          464,  710,  283,  662,  657,-32766, 1240, 1239, 1241,  678,
          304, 1238,  283, -543,   10,  301,  302,  493,-32766,-32766,
        -32766,  663,-32766,  922,-32766,  679,-32766,  710,   -4,-32766,
          373,   40, -508,  956,-32766,-32766,-32766, -275,  731,-32766,
        -32766,-32766,  920,  303,  128, 1238,-32766,  420,  310,    0,
          567,    0,-32766,-32766,-32766,-32766,-32766,    0,-32766,    0,
        -32766,-32766,    0,-32766,    0, 1277, -498,    0,-32766,-32766,
        -32766,-32766, 1279,    0,-32766,-32766,    8, 1238,   24,  372,
        -32766,  420,  920, 1267,-32766,-32766,-32766,  610,-32766,-32766,
        -32766,  939,-32766,  298, -579,-32766,  846,   41,  734,  488,
        -32766,-32766,-32766,-32766,  735,  854,-32766,-32766,  901, 1238,
          574, 1000,-32766,  420,  977,  984,-32766,-32766,-32766,  974,
        -32766,-32766,-32766,  985,-32766,  910,  899,-32766,  972, 1093,
         1096, 1097,-32766,-32766,-32766, 1094, 1095, 1101,-32766,-32766,
         1292, -250, -250, -250,-32766,  420, 1310,  375, 1344,  650,
           28,  267, -578,-32766, -577, -551, -550, -549,  959,  960,
         -492,    1,  835,  523,   29,  910, 1270,   30,  896,  955,
         -110, -110, -110,   39,   43,   47,   72,   76,   77,   78,
           79, -249, -249, -249,   80,   81,  143,  375,  153,  157,
          897,  247,  328,  357,  358,  359,  360,  361,  959,  960,
          922,  362, 1231,  523,  710, -250,  363,  364,  896,  955,
         -110, -110, -110,  365,  366,  367,  369,  529,   28, 1259,
         1260, 1261, 1262, 1256, 1257,  437,  555, 1348, -273, -272,
          835, 1263, 1258,   13, 1270,   14,-32766,   15,   16,   18,
          922,   73, 1238, 1350,  710, -249,  322,  326,  406,-32766,
        -32766,-32766,  484,-32766,  485,-32766,  492,-32766,  495,  496,
        -32766,  497,  498,  502,  503,-32766,-32766,-32766,  504,  511,
         1231,-32766,-32766,  572,  696, 1249, 1190,-32766,  420, 1268,
         1062, 1061, 1042, 1226, 1038,  529,-32766, 1259, 1260, 1261,
         1262, 1256, 1257, -277, -102,   12,   17,   27,  295, 1263,
         1258,  405,  603,  607,  636,  702, 1194, 1244, 1191,   73,
           34, 1323,    0,  320,  322,  326,  371,  711,  714,  718,
          719,  721,  722,  723,  724,    0,  728,  713,    0,  857,
          856,  865,  949,  992,  864, 1349,  948,  946,  947,  950,
         1222,  930,  940,  928,  982,  983,  634, 1347, 1304, 1293,
         1311, 1320,    0, 1207,    0, 1271,    0,  326
    );

    protected array $actionCheck = array(
            2,    3,    4,    5,    6,    7,    0,    9,   10,   11,
           12,   13,    9,   10,   11,   14,    9,   10,   11,   44,
           45,   46,   47,   48,   49,   50,   51,   52,  116,  117,
          118,  119,  120,  121,  122,   37,   38,   30,  116,   32,
           33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
           43,    1,    1,    9,    1,   57,    9,   10,   11,  137,
            1,    9,   10,   11,   50,   51,   52,    8,    1,   71,
           72,   73,   74,   75,   76,   77,   31,   30,   80,   32,
           33,   31,   30,   14,    1,   87,   88,   89,   90,   91,
           92,   93,   94,   95,   96,   97,   98,   99,  100,  101,
          102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
          112,  113,  114,  115,  116,  117,  118,  119,  120,  121,
          122,  123,  124,  125,  126,  116,  128,  129,  130,  131,
          132,  133,   82,   80,  136,  137,  138,  139,  140,  141,
          142,  143,  144,   80,  129,  130,  131,  138,  150,  151,
          152,    1,  154,    8,    2,    3,    4,    5,    6,    7,
          162,    9,   10,   11,   12,   13,    8,  117,  118,    1,
          161,    8,  122,    9,   10,   11,    8,    8,  128,  116,
          117,  118,  119,  120,  121,  122,   51,  137,    8,   37,
           38,   53,   54,   55,   30,   57,   32,   33,   34,   35,
           36,   37,   38,   80,  159,    8,    8,   69,  158,   57,
          159,  161,    9,   10,   11,   80,  163,  167,   83,  160,
          167,  162,    8,   71,   72,   73,   74,   75,   76,   77,
          163,  162,   80,   30,  167,   32,   33,   34,   35,   87,
           88,   89,   90,   91,   92,   93,   94,   95,   96,   97,
           98,   99,  100,  101,  102,  103,  104,  105,  106,  107,
          108,  109,  110,  111,  112,  113,  114,  115,  116,  117,
          118,  119,  120,  121,  122,  123,  124,  125,  126,  156,
          128,  129,  130,  131,  132,  133,  163,    8,  136,  137,
          138,  139,  140,  141,  142,  143,  144,   16,    9,   10,
           11,   31,  150,  151,  152,    8,  154,    2,    3,    4,
            5,    6,    7,  163,    9,   10,   11,   12,   13,   30,
          162,   32,   33,   34,   35,   36,   37,   38,   39,   40,
           41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
           51,   52,   53,   54,   55,    8,   57,   31,    9,   10,
           11,   16,    9,   10,   11,  117,  118,   14,   69,  162,
          122,    8,   57,    9,   10,   11,  128,   97,   30,   30,
            1,   32,   33,   34,   35,   36,   71,   72,   73,   74,
           75,   76,   77,    8,   30,   80,   32,   33,   34,  106,
           80,  108,   87,   88,   89,   90,   91,   92,   93,   94,
           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,
          105,  106,  107,  108,  109,  110,  111,  112,  113,  114,
          115,  116,  117,  118,  119,  120,  121,  122,  123,  124,
          125,  126,   70,  128,  129,  130,  131,  132,  133,    8,
           70,  136,  137,  138,  139,  140,  141,  142,  143,  144,
          116,  106,    1,  108,  116,  150,  151,  152,    2,    3,
            4,    5,    6,    7,   80,  155,  156,  157,   12,   13,
          101,   15,  138,    1,  164,  106,  138,  108,   30,  163,
           37,   38,  113,  106,  107,  116,  117,  118,  119,  120,
          121,  122,  123,  116,    1,  161,  134,  135,   14,  161,
          106,  107,    1,   31,  134,  135,   50,   51,    8,  101,
          116,   70,   56,   85,   58,   59,   60,   61,   62,   63,
           64,   65,   66,   67,   68,  163,   70,   71,   72,   73,
           74,  123,    8,  164,   78,   79,   80,  162,   82,   14,
          156,   70,   86,   87,   88,   89,    8,   91,   97,   93,
            1,   95,  158,   80,   98,   99,   84,    1,    8,  103,
          104,  105,  106,  107,  116,  109,  110,  119,  120,  121,
          122,  115,  116,    8,  146,  134,  135,   84,  122,    8,
          124,  125,  126,   82,    1,   82,  138,   31,   85,  116,
          149,   14,  136,  137,  116,  139,  140,  141,  142,  143,
          144,  145,  161,  122,  163,  134,  135,  151,  152,  161,
          137,  155,  156,  157,  158,    8,  138,  161,    1,    8,
          149,  165,  166,  167,   75,   76,   77,    1,  155,  156,
          157,  159,  161,   84,  163,  163,  122,    1,  137,   90,
           84,   92,  161,   94,    8,   96,  106,  116,  108,  159,
          147,  148,  159,  163,   14,  106,  163,   31,  106,  160,
          108,  162,  161,   14,   70,   82,  117,  118,  167,  138,
           16,  122,    1,    9,   10,  161,  127,  128,  129,  130,
          131,   16,   17,   18,   19,   20,   21,   22,   23,   24,
           25,   26,   27,   28,   29,   37,   38,   75,   76,   82,
          117,  118,   31,   37,   38,  122,   14,  155,  159,   16,
           84,  128,  163,  164,   16,  159,   75,   76,   16,  163,
          137,  101,  102,   16,   59,   60,   70,   16,  134,  135,
          106,  107,   74,  106,  107,   70,   70,   16,   80,    1,
           16,  158,    1,  149,  161,   87,   88,   89,   82,   91,
          167,   93,   86,   95,   31,   84,   98,  163,  111,  112,
           16,  103,  104,  105,    0,    1,   31,  109,  110,   31,
           16,   30,   16,  115,  116,   35,   31,   31,   31,   31,
          163,   30,  124,   31,  167,  159,   37,   38,  122,  163,
          134,  135,   31,   31,   31,   35,  160,   31,  162,  134,
          135,   31,  136,  137,   31,  139,  140,  141,  142,  143,
          144,   31,  154,   31,  149,   31,   31,  151,  152,  163,
           70,   31,   84,   74,   31,   31,   31,  161,  163,   80,
          159,   80,  166,  167,  163,   35,   87,   88,   89,   35,
           91,   35,   93,   35,   95,   35,   37,   98,   84,   37,
           37,   70,  103,  104,  105,   37,   57,  116,  109,  110,
           38,   69,   31,   77,  115,  116,   70,  116,   80,   80,
          106,   92,  108,  124,   83,   97,   89,  113,  113,  138,
           82,  117,  118,   82,  134,  135,  122,   85,  137,  138,
          114,  127,  128,  129,  130,  131,   31,  159,  155,  149,
           97,  163,  161,   96,   90,   74,  155,  156,  157,   94,
          133,   80,  161,  163,  150,  134,  135,   97,   87,   88,
           89,  100,   91,  159,   93,  100,   95,  163,  164,   98,
          149,  159,  149,  128,  103,  104,  105,  162,  164,   74,
          109,  110,    1,  132,  163,   80,  115,  116,  132,   -1,
          153,   -1,   87,   88,   89,  124,   91,   -1,   93,   -1,
           95,  137,   -1,   98,   -1,  146,  149,   -1,  103,  104,
          105,   74,  146,   -1,  109,  110,  149,   80,  149,  149,
          115,  116,    1,  160,   87,   88,   89,  153,   91,  124,
           93,  154,   95,  158,  161,   98,  160,  159,  159,  102,
          103,  104,  105,   74,  159,  159,  109,  110,  159,   80,
           81,  159,  115,  116,  159,  159,   87,   88,   89,  159,
           91,  124,   93,  159,   95,   84,  159,   98,  159,  159,
          159,  159,  103,  104,  105,  159,  159,  159,  109,  110,
          160,  100,  101,  102,  115,  116,  160,  106,  160,  160,
           70,   71,  161,  124,  161,  161,  161,  161,  117,  118,
          161,  161,   82,  122,  161,   84,   86,  161,  127,  128,
          129,  130,  131,  161,  161,  161,  161,  161,  161,  161,
          161,  100,  101,  102,  161,  161,  161,  106,  161,  161,
          164,  161,  161,  161,  161,  161,  161,  161,  117,  118,
          159,  161,  122,  122,  163,  164,  161,  161,  127,  128,
          129,  130,  131,  161,  161,  161,  161,  137,   70,  139,
          140,  141,  142,  143,  144,  161,  161,  164,  162,  162,
           82,  151,  152,  162,   86,  162,   74,  162,  162,  162,
          159,  161,   80,  164,  163,  164,  166,  167,  162,   87,
           88,   89,  162,   91,  162,   93,  162,   95,  162,  162,
           98,  162,  162,  162,  162,  103,  104,  105,  162,  162,
          122,  109,  110,  162,  162,  162,  162,  115,  116,  162,
          162,  162,  162,  162,  162,  137,  124,  139,  140,  141,
          142,  143,  144,  162,  162,  162,  162,  162,  162,  151,
          152,  162,  162,  162,  162,  162,  162,  162,  162,  161,
          163,  162,   -1,  163,  166,  167,  163,  163,  163,  163,
          163,  163,  163,  163,  163,   -1,  163,  163,   -1,  164,
          164,  164,  164,  164,  164,  164,  164,  164,  164,  164,
          164,  164,  164,  164,  164,  164,  164,  164,  164,  164,
          164,  164,   -1,  165,   -1,  166,   -1,  167
    );

    protected array $actionBase = array(
            0,   -2,  152,  549,  764,  941,  981,  751,  617,  310,
          123,  877,  556,  671,  671,  738,  671,  472,  626,  789,
           63,  305,  305,  789,  305,  493,  493,  493,  658,  658,
          658,  658,  749,  749,  897,  897,  929,  865,  831, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062,   51,   45,  451,  692, 1036, 1044,
         1040, 1045, 1034, 1033, 1039, 1041, 1046, 1083, 1084,  795,
         1085, 1086, 1082, 1087, 1042,  889, 1035, 1043,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,   44,  343,  664,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,   52,   52,
           52,  666,  666,   47,  354,  980,  203, 1048, 1048, 1048,
         1048, 1048, 1048, 1048, 1048, 1048,  665,  339,  164,  164,
            7,    7,    7,    7,    7,   50,  369,  583,  -25,  -25,
          -25,  -25,  448,  741,  501,  408,  283,  338,  394,  334,
          334,   14,   14,  531,  531,    9,    9,  531,  531,  531,
          478,  478,  478,  478,  441,  471,  552,  428,  824,   53,
           53,   53,   53,  824,  824,  824,  824,  826, 1089,  824,
          824,  824,  594,  750,  750,  781,  138,  138,  138,  750,
          540,  503,  503,  540,  238,  503,   67,  135,  -78,  805,
          377,  499,  -78,  362,  656,  636,   59,  743,  624,  743,
         1032,  481,  802,  802,  514,  773,  746,  878, 1064, 1049,
          821, 1080,  825, 1081,   15,  370,  745, 1031, 1031, 1031,
         1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1090,  443,
         1032,  384, 1090, 1090, 1090,  443,  443,  443,  443,  443,
          443,  443,  443,  443,  443,  647,  384,  622,  641,  384,
          810,  443,   51,  817,   51,   51,   51,   51,   51,   51,
           51,   51,   51,   51,  780,  316,   51,   45,  150,  150,
          490,   83,  150,  150,  150,  150,   51,   51,   51,   51,
          624,  799,  797,  627,  834,  375,  799,  799,  799,  270,
          158,   69,  197,  740,  760,  345,  788,  788,  801,  900,
          900,  788,  798,  788,  801,  914,  788,  788,  900,  900,
          835,  180,  550,  353,  524,  565,  900,  279,  788,  788,
          788,  788,  816,  571,  788,  214,  198,  788,  788,  816,
          811,  785,  145,  777,  900,  900,  900,  816,  500,  777,
          777,  777,  839,  845,  765,  784,  337,  297,  611,  169,
          822,  784,  784,  788,  538,  765,  784,  765,  784,  837,
          784,  784,  784,  765,  784,  798,  431,  784,  721,  607,
          163,  784,    6,  915,  916,  723,  917,  912,  918,  964,
          919,  923, 1054,  899,  930,  913,  924,  965,  906,  903,
          794,  693,  698,  827,  783,  896,  792,  792,  792,  894,
          792,  792,  792,  792,  792,  792,  792,  792,  693,  823,
          830,  787,  933,  702,  707, 1011,  819,  926, 1088,  932,
         1013,  925,  772,  711,  977,  934,  774, 1050,  935,  936,
          986, 1014,  846, 1017,  963,  796,  979, 1065,  836,  945,
         1055,  792,  915,  923,  735,  913,  924,  906,  903,  770,
          766,  762,  763,  761,  752,  747,  748,  782, 1018,  893,
          833,  880,  940,  895,  693,  886,  971, 1047,  990,  992,
         1053,  803,  791,  888, 1066,  946,  952,  953, 1056, 1019,
         1057,  838,  973,  775,  994,  820, 1067,  996,  997,  999,
         1000, 1058, 1068, 1059,  891, 1060,  849,  814,  966,  807,
         1069,    1,  806,  808,  818,  955,  484,  931, 1061, 1070,
         1071, 1001, 1002, 1006, 1072, 1073,  927,  852,  975,  815,
          976,  967,  855,  856,  525,  813, 1020,  800,  804,  812,
          577,  640, 1074, 1075, 1076,  928,  790,  786,  860,  864,
         1021,  809, 1022, 1077,  649,  867,  724, 1078, 1012,  744,
          754,  281,  654,  335,  756,  779, 1063,  829,  776,  778,
          954,  754,  793,  869, 1079,  870,  871,  872, 1007,  876,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
          456,  456,  456,  456,  456,  456,  305,  305,  305,  305,
          305,  456,  456,  456,  456,  456,  456,  456,  305,  305,
            0,    0,  305,    0,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          473,  473,  289,  289,  473,  289,  473,  473,  473,  473,
          473,  473,  473,  473,  473,    0,  289,  289,  289,  289,
          289,  289,  289,  289,  473,  835,  473,  138,  138,  138,
          138,  473,  473,  473,  -88,  -88,  473,  238,  473,  473,
          138,  138,  473,  473,  473,  473,  473,  473,  473,  473,
          473,  473,  473,    0,    0,  384,  503,  473,  798,  798,
          798,  798,  473,  473,  473,  473,  503,  503,  473,  473,
          473,    0,    0,    0,    0,    0,    0,    0,    0,  384,
            0,    0,  384,    0,    0,  798,  798,  473,  238,  835,
          168,  473,    0,    0,    0,    0,  384,  798,  384,  443,
          788,  503,  503,  788,  443,  443,  150,   51,  168,  620,
          620,  620,  620,    0,    0,  624,  835,  835,  835,  835,
          835,  835,  835,  835,  835,  835,  835,  798,    0,  835,
            0,  798,  798,  798,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,  798,
            0,    0,  900,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,  914,    0,    0,    0,    0,    0,    0,
          798,    0,    0,    0,    0,    0,    0,    0,    0,    0,
          792,  803,    0,  803,    0,  792,  792,  792,    0,    0,
            0,    0,  813,  809
    );

    protected array $actionDefault = array(
            3,32767,  102,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,  100,32767,32767,32767,32767,  597,  597,
          597,  597,32767,32767,  254,  102,32767,32767,  470,  387,
          387,  387,32767,32767,  541,  541,  541,  541,  541,  541,
        32767,32767,32767,32767,32767,32767,  470,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,  100,
        32767,32767,32767,   36,    7,    8,   10,   11,   49,   17,
          324,32767,32767,32767,32767,  102,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,  590,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,  474,  453,
          454,  456,  457,  386,  542,  596,  327,  593,  385,  145,
          339,  329,  242,  330,  258,  475,  259,  476,  479,  480,
          215,  287,  382,  149,  150,  417,  471,  419,  469,  473,
          418,  392,  398,  399,  400,  401,  402,  403,  404,  405,
          406,  407,  408,  409,  410,  390,  391,  472,  450,  449,
          448,32767,32767,  415,  416,32767,  420,32767,32767,32767,
        32767,32767,32767,32767,  102,32767,  389,  423,  421,  422,
          439,  440,  437,  438,  441,32767,32767,32767,  442,  443,
          444,  445,  316,32767,32767,  366,  364,  316,  111,32767,
        32767,  430,  431,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,  535,  447,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,  102,
        32767,  100,  537,  412,  414,  504,  425,  426,  424,  393,
        32767,  511,32767,  102,32767,  513,32767,32767,32767,32767,
        32767,32767,32767,  536,32767,  543,  543,32767,  497,  100,
          195,32767,32767,  512,32767,  195,  195,32767,32767,32767,
        32767,32767,32767,32767,32767,  604,  497,  110,  110,  110,
          110,  110,  110,  110,  110,  110,  110,  110,32767,  195,
          110,32767,32767,32767,  100,  195,  195,  195,  195,  195,
          195,  195,  195,  195,  195,  190,32767,  268,  270,  102,
          558,  195,32767,  516,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,  509,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
          497,  435,  138,32767,  138,  543,  427,  428,  429,  499,
          543,  543,  543,  312,  289,32767,32767,32767,32767,  514,
          514,  100,  100,  100,  100,  509,32767,32767,32767,32767,
          111,   99,   99,   99,   99,   99,  103,  101,32767,32767,
        32767,32767,  223,   99,32767,  101,  101,32767,32767,  223,
          225,  212,  101,  227,32767,  562,  563,  223,  101,  227,
          227,  227,  247,  247,  486,  318,  101,   99,  101,  101,
          197,  318,  318,32767,  101,  486,  318,  486,  318,  199,
          318,  318,  318,  486,  318,32767,  101,  318,  214,   99,
           99,  318,32767,32767,32767,  499,32767,32767,32767,32767,
        32767,32767,32767,  222,32767,32767,32767,32767,32767,32767,
        32767,32767,  530,32767,  547,  560,  433,  434,  436,  545,
          458,  459,  460,  461,  462,  463,  464,  466,  592,32767,
          503,32767,32767,32767,  338,32767,  602,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,  603,32767,  543,32767,32767,32767,
        32767,  432,    9,   74,  492,   42,   43,   51,   57,  520,
          521,  522,  523,  517,  518,  524,  519,32767,32767,  525,
          568,32767,32767,  544,  595,32767,32767,32767,32767,32767,
        32767,  138,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,  530,32767,  136,32767,32767,32767,32767,
        32767,32767,32767,32767,  526,32767,32767,32767,  543,32767,
        32767,32767,32767,  314,  311,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,  543,32767,32767,32767,32767,32767,  291,32767,  308,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,  286,32767,32767,  381,
          499,  294,  296,  297,32767,32767,32767,32767,  360,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
          152,  152,    3,    3,  341,  152,  152,  152,  341,  341,
          152,  341,  341,  341,  152,  152,  152,  152,  152,  152,
          280,  185,  262,  265,  247,  247,  152,  352,  152
    );

    protected array $goto = array(
          196,  196, 1034, 1065,  697,  431,  661,  621,  658,  319,
          706,  425,  313,  314,  335,  576,  430,  336,  432,  638,
          654,  655,  852,  672,  673,  674,  853,  167,  167,  167,
          167,  221,  197,  193,  193,  177,  179,  216,  193,  193,
          193,  193,  193,  194,  194,  194,  194,  194,  194,  188,
          189,  190,  191,  192,  218,  216,  219,  536,  537,  421,
          538,  540,  541,  542,  543,  544,  545,  546,  547, 1136,
          168,  169,  170,  195,  171,  172,  173,  166,  174,  175,
          176,  178,  215,  217,  220,  238,  243,  244,  246,  257,
          258,  259,  260,  261,  262,  263,  264,  268,  269,  270,
          271,  281,  282,  316,  317,  318,  426,  427,  428,  581,
          222,  223,  224,  225,  226,  227,  228,  229,  230,  231,
          232,  233,  234,  235,  236,  180,  237,  181,  198,  199,
          200,  239,  188,  189,  190,  191,  192,  218, 1136,  201,
          182,  183,  184,  202,  198,  185,  240,  203,  201,  165,
          204,  205,  186,  206,  207,  208,  187,  209,  210,  211,
          212,  213,  214,  855,  466,  466,  278,  278,  278,  278,
          623,  623,  351,  466, 1269,  600, 1269, 1269, 1269, 1269,
         1269, 1269, 1269, 1269, 1269, 1287, 1287,  599, 1100, 1287,
          709, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
          508,  700,  458, 1098,  975,  559,  552,  860,  419,  909,
          904,  905,  918,  861,  906,  858,  907,  908,  859,  848,
          827,  912,  354,  354,  354,  354,  396,  399,  560,  601,
          605, 1087, 1082, 1083, 1084,  341,  552,  559,  568,  569,
          344,  579,  602,  616,  617,  408,  409, 1232,  440,  479,
          670,   22,  671,  886,  412,  413,  414,  481,  684,  349,
         1237,  415, 1237, 1107, 1108,  347,  833, 1034, 1034, 1237,
          573,  848, 1034, 1327, 1034, 1034, 1040, 1039, 1034, 1034,
         1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1034, 1319,
         1319, 1319, 1319, 1237,  893,  851,  893,  893, 1237, 1237,
         1237, 1237, 1233, 1234, 1237, 1237, 1237,  833,  355,  833,
          843,  996,  252,  252, 1043, 1044, 1037, 1037,  355,  355,
          681,  952,  394,  926, 1029, 1045, 1046,  927, 1235, 1295,
         1296,  942,  355,  355,  942,  913,  355,  914, 1354,  250,
          250,  250,  250,  245,  253,  548,  548,  548,  548,  554,
          604, 1285, 1285,  355,  355, 1285,  571, 1285, 1285, 1285,
         1285, 1285, 1285, 1285, 1285, 1285,  539,  539,  342,  424,
          539,  611,  539,  539,  539,  539,  539,  539,  539,  539,
          539,  566,  476, 1312, 1313,  733,  637,  639,  325,  308,
          659,  848,  343,  342,  683,  687, 1010,  695,  704, 1006,
          660, 1298,  609,  624,  627,  628,  629,  630,  651,  652,
          653,  708, 1216,  944, 1314, 1315, 1217, 1220,  945, 1221,
         1337, 1337,  686,  352,  353,  868,  553,  563,  450,  450,
          450,  553, 1309,  563, 1309, 1133,  397,  462, 1337, 1058,
          880, 1309, 1185,  867,  500,    5,  501,    6,  469,  580,
          470,  471,  507,  554,  878, 1340, 1340, 1345, 1346,  433,
          438,  550,  666,  550,  433,  682, 1321, 1321, 1321, 1321,
          550,  337, 1041, 1041,  931, 1123,  873,  665, 1052, 1048,
         1049,  619,  845,  876,  324,  275,  324, 1015,  967,  410,
          705,  577,  614, 1305,  456,  872,  403,  664,  994,  969,
          969,  969,  969,  866,  870,  456,  963,  970,  881,  869,
         1070, 1074,  631,  633,  635, 1227, 1230,  958,  615,  978,
          450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
          450,  999, 1018,  450,  971, 1073,  732,  477, 1228, 1307,
         1307, 1073,  736,  968,  551, 1008, 1003,  882,  694, 1075,
         1071,  829,  255,  255,  980,    0, 1118,    0, 1013, 1013,
          694,    0,    0,    0,  694, 1116,  885
    );

    protected array $gotoCheck = array(
           42,   42,   73,  127,   73,   66,   66,   56,   56,   66,
            9,   66,   66,   66,   66,   66,   66,   66,   66,   66,
           86,   86,   26,   86,   86,   86,   27,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   15,  149,  149,   23,   23,   23,   23,
          108,  108,   97,  149,  108,  130,  108,  108,  108,  108,
          108,  108,  108,  108,  108,  170,  170,    8,    8,  170,
            8,  170,  170,  170,  170,  170,  170,  170,  170,  170,
            8,    8,   83,    8,   49,   76,   76,   15,   43,   15,
           15,   15,   15,   15,   15,   15,   15,   15,   15,   22,
            6,   15,   24,   24,   24,   24,   59,   59,   59,   59,
           59,   15,   15,   15,   15,   76,   76,   76,   76,   76,
           76,   76,   76,   76,   76,   82,   82,   20,   83,   84,
           82,   76,   82,   45,   82,   82,   82,   84,   82,  179,
           73,   82,   73,  144,  144,   82,   12,   73,   73,   73,
          172,   22,   73,  181,   73,   73,  118,  118,   73,   73,
           73,   73,   73,   73,   73,   73,   73,   73,   73,    9,
            9,    9,    9,   73,   25,   25,   25,   25,   73,   73,
           73,   73,   20,   20,   73,   73,   73,   12,   14,   12,
           20,  103,    5,    5,  119,  119,   89,   89,   14,   14,
           89,   89,   62,   73,   89,   89,   89,   73,   20,   20,
           20,    9,   14,   14,    9,   65,   14,   65,   14,    5,
            5,    5,    5,    5,    5,  107,  107,  107,  107,   14,
          107,  171,  171,   14,   14,  171,  104,  171,  171,  171,
          171,  171,  171,  171,  171,  171,  173,  173,  168,   13,
          173,   13,  173,  173,  173,  173,  173,  173,  173,  173,
          173,   48,  176,  176,  176,   48,   48,   48,  169,  169,
           48,   22,  168,  168,   48,   48,   48,   48,   48,   48,
           64,   14,   81,   81,   81,   81,   81,   81,   81,   81,
           81,   81,   79,   79,  178,  178,   79,   79,   79,   79,
          182,  182,   14,   97,   97,   35,    9,    9,   23,   23,
           23,    9,  130,    9,  130,  150,    9,    9,  182,  114,
           35,  130,  151,   35,  155,   46,  155,   46,    9,    9,
            9,    9,  155,   14,    9,  182,  182,    9,    9,  117,
          113,   19,  120,   19,  117,  116,  130,  130,  130,  130,
           19,   29,  117,  117,   17,   17,   39,  117,  117,  117,
          117,   17,   18,    9,   24,   24,   24,   17,   93,   93,
           93,    2,    2,  130,   19,   17,   28,   17,   17,   19,
           19,   19,   19,   17,   37,   19,   19,   19,   16,   16,
           16,   16,   85,   85,   85,   17,   14,   92,   80,   16,
           23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
           23,   50,  110,   23,   50,  130,   50,  157,  160,  130,
          130,  130,   99,   16,   50,   50,   50,   41,    7,  132,
          129,    7,    5,    5,   96,   -1,  147,   -1,  107,  107,
            7,   -1,   -1,   -1,    7,   16,   16
    );

    protected array $gotoBase = array(
            0,    0, -221,    0,    0,  311,  200,  541,  179,  -10,
            0,    0,  -30,   32,   11, -185,   56,    9,  173,  196,
         -146,    0,  -59,  163,  219,  291,   18,   22,  159,  175,
            0,    0,    0,    0,    0,   54,    0,  165,    0,  153,
            0,  106,   -1,  189,    0,  230, -291,    0, -330,  186,
          519,    0,    0,    0,    0,    0,  -33,    0,    0,  181,
            0,    0,  280,    0,  158,  321, -236,    0,    0,    0,
            0,    0,    0,   -5,    0,    0, -140,    0,    0,    4,
          174,   44, -246,  -76, -220,   33, -698,    0,    0,   37,
            0,    0,  188,  184,    0,    0,  111, -311,    0,  135,
            0,    0,    0,  276,  313,    0,    0,  317,  -71,    0,
          162,    0,    0,  183,  166,    0,  182,  187,   -3,   29,
          172,    0,    0,    0,    0,    0,    0,    1,    0,  176,
          167,    0,  107,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,  -12,    0,    0,  112,    0,  130,
          190,  168,    0,    0,    0,  -51,    0,   97,    0,    0,
          169,    0,    0,    0,    0,    0,    0,    0,   71,   67,
          -56,  110,  241,  125,    0,    0,   82,    0,   42,  229,
            0,  242,  113,    0,    0
    );

    protected array $gotoDefault = array(
        -32768,  512,  740,    4,  741,  935,  816,  825,  597,  530,
          707,  348,  625,  422, 1303,  911, 1122,  578,  844, 1246,
         1254,  457,  847,  330,  730,  923,  894,  895,  400,  386,
          392,  398,  649,  626,  494,  879,  453,  871,  486,  874,
          452,  883,  164,  418,  510,  887,    3,  890,  557,  921,
          973,  387,  898,  388,  677,  900,  562,  902,  903,  395,
          401,  402, 1127,  570,  622,  915,  256,  564,  916,  385,
          917,  925,  390,  393,  688,  465,  505,  499,  411, 1102,
          565,  608,  646,  447,  473,  620,  632,  618,  480,  434,
          416,  329,  957,  965,  487,  463,  979,  350,  987,  738,
         1135,  640,  489,  995,  641, 1002, 1005,  531,  532,  478,
         1017,  272, 1020,  490,   19,  667, 1031, 1032,  668,  642,
         1054,  643,  669,  644, 1056,  472,  598, 1064,  454, 1072,
         1291,  455, 1076,  266, 1079,  277,  417,  435, 1085, 1086,
            9, 1092,  698,  699,   11,  276,  509, 1117,  689,  451,
         1134,  439, 1204, 1206,  558,  491, 1224, 1223,  680,  506,
         1229,  448, 1294,  449,  533,  474,  315,  534, 1338,  307,
          333,  312,  549,  294,  334,  535,  475, 1300, 1308,  331,
           31, 1328, 1339,  575,  613
    );

    protected array $ruleToNonTerminal = array(
            0,    1,    3,    3,    2,    5,    5,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    7,    7,    7,
            7,    7,    7,    7,    7,    8,    8,    9,   10,   11,
           11,   11,   12,   12,   13,   13,   14,   15,   15,   16,
           16,   17,   17,   18,   18,   21,   21,   22,   23,   23,
           24,   24,    4,    4,    4,    4,    4,    4,    4,    4,
            4,    4,    4,   29,   29,   30,   30,   32,   34,   34,
           28,   36,   36,   33,   38,   38,   35,   35,   37,   37,
           39,   39,   31,   40,   40,   41,   43,   44,   44,   45,
           45,   46,   46,   48,   47,   47,   47,   47,   49,   49,
           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
           49,   49,   25,   25,   50,   69,   69,   72,   72,   71,
           70,   70,   63,   75,   75,   76,   76,   77,   77,   78,
           78,   79,   79,   80,   80,   26,   26,   27,   27,   27,
           27,   27,   88,   88,   90,   90,   83,   83,   91,   91,
           92,   92,   92,   84,   84,   87,   87,   85,   85,   93,
           94,   94,   57,   57,   65,   65,   68,   68,   68,   67,
           95,   95,   96,   58,   58,   58,   58,   97,   97,   98,
           98,   99,   99,  100,  101,  101,  102,  102,  103,  103,
           55,   55,   51,   51,  105,   53,   53,  106,   52,   52,
           54,   54,   64,   64,   64,   64,   81,   81,  109,  109,
          111,  111,  112,  112,  112,  112,  110,  110,  110,  114,
          114,  114,  114,   89,   89,  117,  117,  117,  118,  118,
          115,  115,  119,  119,  121,  121,  122,  122,  116,  123,
          123,  120,  124,  124,  124,  124,  113,  113,   82,   82,
           82,   20,   20,   20,  126,  125,  125,  127,  127,  127,
          127,   60,  128,  128,  129,   61,  131,  131,  132,  132,
          133,  133,   86,  134,  134,  134,  134,  134,  134,  134,
          139,  139,  140,  140,  141,  141,  141,  141,  141,  142,
          143,  143,  138,  138,  135,  135,  137,  137,  145,  145,
          144,  144,  144,  144,  144,  144,  144,  136,  146,  146,
          148,  147,  147,   62,  104,  149,  149,   56,   56,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,  156,  150,  150,  155,  155,  158,  159,
          159,  160,  161,  162,  162,  162,  162,   19,   19,   73,
           73,   73,   73,  151,  151,  151,  151,  164,  164,  152,
          152,  154,  154,  154,  157,  157,  170,  170,  170,  170,
          170,  170,  170,  170,  170,  171,  171,  171,  108,  173,
          173,  173,  173,  153,  153,  153,  153,  153,  153,  153,
          153,   59,   59,  167,  167,  167,  167,  174,  174,  163,
          163,  163,  175,  175,  175,  175,  175,  175,   74,   74,
           66,   66,   66,   66,  130,  130,  130,  130,  178,  177,
          166,  166,  166,  166,  166,  166,  166,  165,  165,  165,
          176,  176,  176,  176,  107,  172,  180,  180,  179,  179,
          181,  181,  181,  181,  181,  181,  181,  181,  169,  169,
          169,  169,  168,  183,  182,  182,  182,  182,  182,  182,
          182,  182,  184,  184,  184,  184
    );

    protected array $ruleToLength = array(
            1,    1,    2,    0,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    0,
            1,    0,    1,    1,    2,    1,    3,    4,    1,    2,
            0,    1,    1,    1,    1,    4,    3,    5,    4,    3,
            4,    2,    3,    1,    1,    7,    6,    2,    3,    1,
            2,    3,    1,    2,    3,    1,    1,    3,    1,    3,
            1,    2,    2,    3,    1,    3,    2,    3,    1,    3,
            3,    2,    0,    1,    1,    1,    1,    1,    3,    7,
           10,    5,    7,    9,    5,    3,    3,    3,    3,    3,
            3,    1,    2,    5,    7,    9,    6,    5,    6,    3,
            2,    1,    1,    1,    1,    0,    2,    1,    3,    8,
            0,    4,    2,    1,    3,    0,    1,    0,    1,    0,
            1,    3,    1,    1,    1,    8,    9,    7,    8,    7,
            6,    8,    0,    2,    0,    2,    1,    2,    1,    2,
            1,    1,    1,    0,    2,    0,    2,    0,    2,    2,
            1,    3,    1,    4,    1,    4,    1,    1,    4,    2,
            1,    3,    3,    3,    4,    4,    5,    0,    2,    4,
            3,    1,    1,    7,    0,    2,    1,    3,    3,    4,
            1,    4,    0,    2,    5,    0,    2,    6,    0,    2,
            0,    3,    1,    2,    1,    1,    2,    0,    1,    3,
            0,    2,    1,    1,    1,    1,    6,    8,    6,    1,
            2,    1,    1,    1,    1,    1,    1,    1,    1,    3,
            3,    3,    1,    3,    3,    3,    3,    3,    1,    3,
            3,    1,    1,    2,    1,    1,    0,    1,    0,    2,
            2,    2,    4,    3,    1,    1,    3,    1,    2,    2,
            3,    2,    3,    1,    1,    2,    3,    1,    1,    3,
            2,    0,    1,    5,    5,    6,   10,    3,    5,    1,
            1,    3,    0,    2,    4,    5,    4,    4,    4,    3,
            1,    1,    1,    1,    1,    1,    0,    1,    1,    2,
            1,    1,    1,    1,    1,    1,    1,    2,    1,    3,
            1,    1,    3,    2,    2,    3,    1,    0,    1,    1,
            3,    3,    3,    4,    4,    1,    1,    2,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
            3,    2,    2,    2,    2,    3,    3,    3,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
            3,    3,    3,    2,    2,    2,    2,    3,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    5,    4,
            3,    4,    4,    2,    2,    4,    2,    2,    2,    2,
            2,    2,    2,    2,    2,    2,    2,    1,    3,    2,
            1,    2,    4,    2,    2,    8,    9,    8,    9,    9,
           10,    9,   10,    8,    3,    2,    0,    4,    2,    1,
            3,    2,    1,    2,    2,    2,    4,    1,    1,    1,
            1,    1,    1,    1,    1,    3,    1,    1,    1,    0,
            3,    0,    1,    1,    0,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    3,    5,    3,    3,    4,
            1,    1,    3,    1,    1,    1,    1,    1,    3,    2,
            3,    0,    1,    1,    3,    1,    1,    1,    1,    1,
            3,    1,    1,    4,    4,    1,    4,    4,    0,    1,
            1,    1,    3,    3,    1,    4,    2,    2,    1,    3,
            1,    4,    4,    3,    3,    3,    3,    1,    3,    1,
            1,    3,    1,    1,    4,    1,    1,    1,    3,    1,
            1,    2,    1,    3,    4,    3,    2,    0,    2,    2,
            1,    2,    1,    1,    1,    4,    3,    3,    3,    3,
            6,    3,    1,    1,    2,    1
    );

    protected function initReduceCallbacks(): void {
        $this->reduceCallbacks = [
            0 => null,
            1 => static function ($self, $stackPos) {
                 $self->semValue = $self->handleNamespaces($self->semStack[$stackPos-(1-1)]);
            },
            2 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;
            },
            3 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            4 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            5 => null,
            6 => null,
            7 => null,
            8 => null,
            9 => null,
            10 => null,
            11 => null,
            12 => null,
            13 => null,
            14 => null,
            15 => null,
            16 => null,
            17 => null,
            18 => null,
            19 => null,
            20 => null,
            21 => null,
            22 => null,
            23 => null,
            24 => null,
            25 => null,
            26 => null,
            27 => null,
            28 => null,
            29 => null,
            30 => null,
            31 => null,
            32 => null,
            33 => null,
            34 => null,
            35 => null,
            36 => null,
            37 => null,
            38 => null,
            39 => null,
            40 => null,
            41 => null,
            42 => null,
            43 => null,
            44 => null,
            45 => null,
            46 => null,
            47 => null,
            48 => null,
            49 => null,
            50 => null,
            51 => null,
            52 => null,
            53 => null,
            54 => null,
            55 => null,
            56 => null,
            57 => null,
            58 => null,
            59 => null,
            60 => null,
            61 => null,
            62 => null,
            63 => null,
            64 => null,
            65 => null,
            66 => null,
            67 => null,
            68 => null,
            69 => null,
            70 => null,
            71 => null,
            72 => null,
            73 => null,
            74 => null,
            75 => null,
            76 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; if ($self->semValue === "<?=") $self->emitError(new Error('Cannot use "<?=" as an identifier', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));
            },
            77 => null,
            78 => null,
            79 => null,
            80 => null,
            81 => null,
            82 => null,
            83 => null,
            84 => null,
            85 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            86 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            87 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            88 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            89 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            90 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            91 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            92 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            93 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            94 => null,
            95 => static function ($self, $stackPos) {
                 $self->semValue = new Name(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            96 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            97 => static function ($self, $stackPos) {
                 /* nothing */
            },
            98 => static function ($self, $stackPos) {
                 /* nothing */
            },
            99 => static function ($self, $stackPos) {
                 /* nothing */
            },
            100 => static function ($self, $stackPos) {
                 $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));
            },
            101 => null,
            102 => null,
            103 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Attribute($self->semStack[$stackPos-(1-1)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            104 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Attribute($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            105 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            106 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            107 => static function ($self, $stackPos) {
                 $self->semValue = new Node\AttributeGroup($self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            108 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            109 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            110 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            111 => null,
            112 => null,
            113 => null,
            114 => null,
            115 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            116 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos-(3-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON);
            $self->checkNamespace($self->semValue);
            },
            117 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos-(5-2)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED);
            $self->checkNamespace($self->semValue);
            },
            118 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_(null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED);
            $self->checkNamespace($self->semValue);
            },
            119 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Use_($self->semStack[$stackPos-(3-2)], Stmt\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            120 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Use_($self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            121 => null,
            122 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Const_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            123 => static function ($self, $stackPos) {
                 $self->semValue = Stmt\Use_::TYPE_FUNCTION;
            },
            124 => static function ($self, $stackPos) {
                 $self->semValue = Stmt\Use_::TYPE_CONSTANT;
            },
            125 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-6)], $self->semStack[$stackPos-(7-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            126 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            127 => null,
            128 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            129 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            130 => null,
            131 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            132 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            133 => null,
            134 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            135 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            136 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(1-1));
            },
            137 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(3-3));
            },
            138 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(1-1));
            },
            139 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(3-3));
            },
            140 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->semValue->type = Stmt\Use_::TYPE_NORMAL;
            },
            141 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)]; $self->semValue->type = $self->semStack[$stackPos-(2-1)];
            },
            142 => null,
            143 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            144 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            145 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            146 => null,
            147 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            148 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            149 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            150 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            151 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;
            },
            152 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            153 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            154 => null,
            155 => null,
            156 => null,
            157 => static function ($self, $stackPos) {
                 throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            158 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Block($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            159 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\If_($self->semStack[$stackPos-(7-3)], ['stmts' => $self->semStack[$stackPos-(7-5)], 'elseifs' => $self->semStack[$stackPos-(7-6)], 'else' => $self->semStack[$stackPos-(7-7)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            160 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\If_($self->semStack[$stackPos-(10-3)], ['stmts' => $self->semStack[$stackPos-(10-6)], 'elseifs' => $self->semStack[$stackPos-(10-7)], 'else' => $self->semStack[$stackPos-(10-8)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            161 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\While_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            162 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Do_($self->semStack[$stackPos-(7-5)], $self->semStack[$stackPos-(7-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            163 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\For_(['init' => $self->semStack[$stackPos-(9-3)], 'cond' => $self->semStack[$stackPos-(9-5)], 'loop' => $self->semStack[$stackPos-(9-7)], 'stmts' => $self->semStack[$stackPos-(9-9)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            164 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Switch_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            165 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Break_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            166 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Continue_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            167 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Return_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            168 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Global_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            169 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Static_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            170 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Echo_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            171 => static function ($self, $stackPos) {

        $self->semValue = new Stmt\InlineHTML($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
        $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos-(1-1)));

            },
            172 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Expression($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            173 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Unset_($self->semStack[$stackPos-(5-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            174 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-5)][0], ['keyVar' => null, 'byRef' => $self->semStack[$stackPos-(7-5)][1], 'stmts' => $self->semStack[$stackPos-(7-7)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            175 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(9-3)], $self->semStack[$stackPos-(9-7)][0], ['keyVar' => $self->semStack[$stackPos-(9-5)], 'byRef' => $self->semStack[$stackPos-(9-7)][1], 'stmts' => $self->semStack[$stackPos-(9-9)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            176 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(6-3)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(6-4)],  $self->tokenEndStack[$stackPos-(6-4)])), ['stmts' => $self->semStack[$stackPos-(6-6)]], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            177 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Declare_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            178 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TryCatch($self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-5)], $self->semStack[$stackPos-(6-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])); $self->checkTryCatch($self->semValue);
            },
            179 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Goto_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            180 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Label($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            181 => static function ($self, $stackPos) {
                 $self->semValue = null; /* means: no statement */
            },
            182 => null,
            183 => static function ($self, $stackPos) {
                 $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]);
            },
            184 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(1-1)] instanceof Stmt\Block) { $self->semValue = $self->semStack[$stackPos-(1-1)]->stmts; } else if ($self->semStack[$stackPos-(1-1)] === null) { $self->semValue = []; } else { $self->semValue = [$self->semStack[$stackPos-(1-1)]]; };
            },
            185 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            186 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            187 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            188 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            189 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Catch_($self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-7)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            190 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            191 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Finally_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            192 => null,
            193 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            194 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            195 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            196 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            197 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            198 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            199 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            200 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            201 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            202 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            203 => null,
            204 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            205 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Function_($self->semStack[$stackPos-(8-3)], ['byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-5)], 'returnType' => $self->semStack[$stackPos-(8-7)], 'stmts' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            206 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Function_($self->semStack[$stackPos-(9-4)], ['byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-6)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            207 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Class_($self->semStack[$stackPos-(7-2)], ['type' => $self->semStack[$stackPos-(7-1)], 'extends' => $self->semStack[$stackPos-(7-3)], 'implements' => $self->semStack[$stackPos-(7-4)], 'stmts' => $self->semStack[$stackPos-(7-6)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClass($self->semValue, $stackPos-(7-2));
            },
            208 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Class_($self->semStack[$stackPos-(8-3)], ['type' => $self->semStack[$stackPos-(8-2)], 'extends' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClass($self->semValue, $stackPos-(8-3));
            },
            209 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Interface_($self->semStack[$stackPos-(7-3)], ['extends' => $self->semStack[$stackPos-(7-4)], 'stmts' => $self->semStack[$stackPos-(7-6)], 'attrGroups' => $self->semStack[$stackPos-(7-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            $self->checkInterface($self->semValue, $stackPos-(7-3));
            },
            210 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Trait_($self->semStack[$stackPos-(6-3)], ['stmts' => $self->semStack[$stackPos-(6-5)], 'attrGroups' => $self->semStack[$stackPos-(6-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            211 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Enum_($self->semStack[$stackPos-(8-3)], ['scalarType' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            $self->checkEnum($self->semValue, $stackPos-(8-3));
            },
            212 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            213 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            214 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            215 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            216 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            217 => null,
            218 => null,
            219 => static function ($self, $stackPos) {
                 $self->checkClassModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            220 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::ABSTRACT;
            },
            221 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::FINAL;
            },
            222 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            223 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            224 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            225 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            226 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            227 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            228 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            229 => null,
            230 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            231 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            232 => null,
            233 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            234 => null,
            235 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            236 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(1-1)] instanceof Stmt\Block) { $self->semValue = $self->semStack[$stackPos-(1-1)]->stmts; } else if ($self->semStack[$stackPos-(1-1)] === null) { $self->semValue = []; } else { $self->semValue = [$self->semStack[$stackPos-(1-1)]]; };
            },
            237 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            238 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            239 => null,
            240 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            241 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            242 => static function ($self, $stackPos) {
                 $self->semValue = new Node\DeclareItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            243 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            244 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-3)];
            },
            245 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            246 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(5-3)];
            },
            247 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            248 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            249 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Case_($self->semStack[$stackPos-(4-2)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            250 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Case_(null, $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            251 => null,
            252 => null,
            253 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Match_($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            254 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            255 => null,
            256 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            257 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            258 => static function ($self, $stackPos) {
                 $self->semValue = new Node\MatchArm($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            259 => static function ($self, $stackPos) {
                 $self->semValue = new Node\MatchArm(null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            260 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            261 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            262 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            263 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            264 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            265 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            266 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            267 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);
            },
            268 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            269 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Else_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            270 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            271 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Else_($self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);
            },
            272 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);
            },
            273 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(2-2)], true);
            },
            274 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);
            },
            275 => static function ($self, $stackPos) {
                 $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos-(1-1)]), false);
            },
            276 => null,
            277 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            278 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            279 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            280 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            281 => static function ($self, $stackPos) {
                 $self->checkModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            282 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PUBLIC;
            },
            283 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PROTECTED;
            },
            284 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PRIVATE;
            },
            285 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            286 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param($self->semStack[$stackPos-(6-6)], null, $self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-4)], $self->semStack[$stackPos-(6-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-1)]);
            $self->checkParam($self->semValue);
            },
            287 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param($self->semStack[$stackPos-(8-6)], $self->semStack[$stackPos-(8-8)], $self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(8-2)], $self->semStack[$stackPos-(8-1)]);
            $self->checkParam($self->semValue);
            },
            288 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])), null, $self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-4)], $self->semStack[$stackPos-(6-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-1)]);
            },
            289 => null,
            290 => static function ($self, $stackPos) {
                 $self->semValue = new Node\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            291 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            292 => null,
            293 => null,
            294 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            295 => static function ($self, $stackPos) {
                 $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos-(1-1)]);
            },
            296 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            297 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            298 => null,
            299 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            300 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            301 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            302 => null,
            303 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            304 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            305 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            306 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            307 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            308 => static function ($self, $stackPos) {
                 $self->semValue = new Node\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            309 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            310 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            311 => static function ($self, $stackPos) {
                 $self->semValue = new Node\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            312 => null,
            313 => static function ($self, $stackPos) {
                 $self->semValue = new Node\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            314 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            315 => null,
            316 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            317 => null,
            318 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            319 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            320 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            321 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            322 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            323 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-2)]);
            },
            324 => static function ($self, $stackPos) {
                 $self->semValue = new Node\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            325 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            326 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            327 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(1-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            328 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(2-2)], true, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            329 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(2-2)], false, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            330 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(3-3)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(3-1)]);
            },
            331 => null,
            332 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            333 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            334 => null,
            335 => null,
            336 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            337 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            338 => static function ($self, $stackPos) {
                 $self->semValue = new Node\StaticVar($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            339 => static function ($self, $stackPos) {
                 $self->semValue = new Node\StaticVar($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            340 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)]; } else { $self->semValue = $self->semStack[$stackPos-(2-1)]; }
            },
            341 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            342 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            343 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Property($self->semStack[$stackPos-(5-2)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-1)]);
            $self->checkProperty($self->semValue, $stackPos-(5-2));
            },
            344 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(5-1)]);
            $self->checkClassConst($self->semValue, $stackPos-(5-2));
            },
            345 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos-(6-5)], $self->semStack[$stackPos-(6-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-1)], $self->semStack[$stackPos-(6-4)]);
            $self->checkClassConst($self->semValue, $stackPos-(6-2));
            },
            346 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassMethod($self->semStack[$stackPos-(10-5)], ['type' => $self->semStack[$stackPos-(10-2)], 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-7)], 'returnType' => $self->semStack[$stackPos-(10-9)], 'stmts' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClassMethod($self->semValue, $stackPos-(10-2));
            },
            347 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUse($self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            348 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\EnumCase($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            349 => static function ($self, $stackPos) {
                 $self->semValue = null; /* will be skipped */
            },
            350 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            351 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            352 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            353 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            354 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Precedence($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            355 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(5-1)][0], $self->semStack[$stackPos-(5-1)][1], $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            356 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], $self->semStack[$stackPos-(4-3)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            357 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            358 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            359 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            360 => null,
            361 => static function ($self, $stackPos) {
                 $self->semValue = array(null, $self->semStack[$stackPos-(1-1)]);
            },
            362 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            363 => null,
            364 => null,
            365 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            366 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            367 => null,
            368 => null,
            369 => static function ($self, $stackPos) {
                 $self->checkModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            370 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PUBLIC;
            },
            371 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PROTECTED;
            },
            372 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PRIVATE;
            },
            373 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::STATIC;
            },
            374 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::ABSTRACT;
            },
            375 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::FINAL;
            },
            376 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            377 => null,
            378 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            379 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            380 => static function ($self, $stackPos) {
                 $self->semValue = new Node\VarLikeIdentifier(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            381 => static function ($self, $stackPos) {
                 $self->semValue = new Node\PropertyItem($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            382 => static function ($self, $stackPos) {
                 $self->semValue = new Node\PropertyItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            383 => null,
            384 => null,
            385 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            386 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            387 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            388 => null,
            389 => null,
            390 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            391 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->fixupArrayDestructuring($self->semStack[$stackPos-(3-1)]), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            392 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            393 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignRef($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            394 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignRef($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            if (!$self->phpVersion->allowsAssignNewByReference()) {
                $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));
            }

            },
            395 => null,
            396 => null,
            397 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Clone_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            398 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Plus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            399 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Minus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            400 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Mul($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            401 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Div($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            402 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Concat($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            403 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Mod($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            404 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            405 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            406 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            407 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\ShiftLeft($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            408 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\ShiftRight($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            409 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Pow($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            410 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Coalesce($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            411 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PostInc($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            412 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PreInc($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            413 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PostDec($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            414 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PreDec($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            415 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BooleanOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            416 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BooleanAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            417 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            418 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            419 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            420 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            421 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            422 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            423 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            424 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Concat($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            425 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Plus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            426 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Minus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            427 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Mul($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            428 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Div($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            429 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Mod($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            430 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\ShiftLeft($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            431 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\ShiftRight($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            432 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Pow($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            433 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\UnaryPlus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            434 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\UnaryMinus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            435 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BooleanNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            436 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BitwiseNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            437 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Identical($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            438 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\NotIdentical($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            439 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Equal($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            440 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\NotEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            441 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Spaceship($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            442 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Smaller($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            443 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\SmallerOrEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            444 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Greater($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            445 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\GreaterOrEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            446 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Instanceof_($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            447 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            448 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Ternary($self->semStack[$stackPos-(5-1)], $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            449 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Ternary($self->semStack[$stackPos-(4-1)], null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            450 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Coalesce($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            451 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Isset_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            452 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Empty_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            453 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            454 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_INCLUDE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            455 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Eval_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            456 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            457 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            458 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            459 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
            $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos-(2-1)]);
            $self->semValue = new Expr\Cast\Double($self->semStack[$stackPos-(2-2)], $attrs);
            },
            460 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            461 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            462 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            463 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            464 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            465 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
            $attrs['kind'] = strtolower($self->semStack[$stackPos-(2-1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE;
            $self->semValue = new Expr\Exit_($self->semStack[$stackPos-(2-2)], $attrs);
            },
            466 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ErrorSuppress($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            467 => null,
            468 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ShellExec($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            469 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Print_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            470 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            471 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_($self->semStack[$stackPos-(2-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            472 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_($self->semStack[$stackPos-(4-4)], $self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            473 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\YieldFrom($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            474 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Throw_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            475 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => false, 'byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-4)], 'returnType' => $self->semStack[$stackPos-(8-6)], 'expr' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            476 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => true, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'returnType' => $self->semStack[$stackPos-(9-7)], 'expr' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            477 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => false, 'byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-4)], 'uses' => $self->semStack[$stackPos-(8-6)], 'returnType' => $self->semStack[$stackPos-(8-7)], 'stmts' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            478 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => true, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'uses' => $self->semStack[$stackPos-(9-7)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            479 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => false, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'returnType' => $self->semStack[$stackPos-(9-7)], 'expr' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            480 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => true, 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-6)], 'returnType' => $self->semStack[$stackPos-(10-8)], 'expr' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            481 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => false, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'uses' => $self->semStack[$stackPos-(9-7)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            482 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => true, 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-6)], 'uses' => $self->semStack[$stackPos-(10-8)], 'returnType' => $self->semStack[$stackPos-(10-9)], 'stmts' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            483 => static function ($self, $stackPos) {
                 $self->semValue = array(new Stmt\Class_(null, ['type' => $self->semStack[$stackPos-(8-2)], 'extends' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos])), $self->semStack[$stackPos-(8-3)]);
            $self->checkClass($self->semValue[0], -1);
            },
            484 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\New_($self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            485 => static function ($self, $stackPos) {
                 list($class, $ctorArgs) = $self->semStack[$stackPos-(2-2)]; $self->semValue = new Expr\New_($class, $ctorArgs, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            486 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            487 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-3)];
            },
            488 => null,
            489 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            490 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            491 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ClosureUse($self->semStack[$stackPos-(2-2)], $self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            492 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            493 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            494 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            495 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            496 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            497 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            498 => null,
            499 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            500 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            501 => static function ($self, $stackPos) {
                 $self->semValue = new Name\FullyQualified(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            502 => static function ($self, $stackPos) {
                 $self->semValue = new Name\Relative(substr($self->semStack[$stackPos-(1-1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            503 => null,
            504 => null,
            505 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            506 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            507 => null,
            508 => null,
            509 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            510 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            511 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            512 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]); foreach ($self->semValue as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); } };
            },
            513 => static function ($self, $stackPos) {
                 foreach ($self->semStack[$stackPos-(1-1)] as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); } }; $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            514 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            515 => null,
            516 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ConstFetch($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            517 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Line($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            518 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\File($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            519 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Dir($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            520 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Class_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            521 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Trait_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            522 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Method($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            523 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Function_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            524 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            525 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            526 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(5-1)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            527 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            528 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT;
            $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs);
            },
            529 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG;
            $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs);
            $self->createdArrays->attach($self->semValue);
            },
            530 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->attach($self->semValue);
            },
            531 => static function ($self, $stackPos) {
                 $self->semValue = Scalar\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());
            },
            532 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
            foreach ($self->semStack[$stackPos-(3-2)] as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', $self->phpVersion->supportsUnicodeEscapes()); } }; $self->semValue = new Scalar\InterpolatedString($self->semStack[$stackPos-(3-2)], $attrs);
            },
            533 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseLNumber($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals());
            },
            534 => static function ($self, $stackPos) {
                 $self->semValue = Scalar\Float_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            535 => null,
            536 => null,
            537 => null,
            538 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)]), true);
            },
            539 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(2-1)], '', $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(2-2)],  $self->tokenEndStack[$stackPos-(2-2)]), true);
            },
            540 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)]), true);
            },
            541 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            542 => null,
            543 => null,
            544 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            545 => null,
            546 => null,
            547 => null,
            548 => null,
            549 => null,
            550 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            551 => null,
            552 => null,
            553 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            554 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            555 => null,
            556 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\MethodCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            557 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafeMethodCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            558 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            559 => null,
            560 => null,
            561 => null,
            562 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            563 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            564 => null,
            565 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            566 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            567 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos])), $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            568 => static function ($self, $stackPos) {
                 $var = $self->semStack[$stackPos-(1-1)]->name; $self->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])) : $var;
            },
            569 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            570 => null,
            571 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            572 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            573 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            574 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            575 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            576 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            577 => null,
            578 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            579 => null,
            580 => null,
            581 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            582 => null,
            583 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            584 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\List_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])); $self->semValue->setAttribute('kind', Expr\List_::KIND_LIST);
            $self->postprocessList($self->semValue);
            },
            585 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $end = count($self->semValue)-1; if ($self->semValue[$end]->value instanceof Expr\Error) array_pop($self->semValue);
            },
            586 => null,
            587 => static function ($self, $stackPos) {
                 /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */
            },
            588 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            589 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            590 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            591 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(2-2)], null, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            592 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            593 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(3-3)], $self->semStack[$stackPos-(3-1)], false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            594 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(4-4)], $self->semStack[$stackPos-(4-1)], true, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            595 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(3-3)], $self->semStack[$stackPos-(3-1)], false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            596 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(2-2)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), true);
            },
            597 => static function ($self, $stackPos) {
                 /* Create an Error node now to remember the position. We'll later either report an error,
             or convert this into a null element, depending on whether this is a creation or destructuring context. */
          $attrs = $self->createEmptyElemAttributes($self->tokenPos);
          $self->semValue = new Node\ArrayItem(new Expr\Error($attrs), null, false, $attrs);
            },
            598 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            599 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            600 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            601 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)]);
            },
            602 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]); $attrs['rawValue'] = $self->semStack[$stackPos-(1-1)]; $self->semValue = new Node\InterpolatedStringPart($self->semStack[$stackPos-(1-1)], $attrs);
            },
            603 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            604 => null,
            605 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            606 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            607 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            608 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            609 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            610 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            611 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            612 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\String_($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            613 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseNumString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            614 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            615 => null,
        ];
    }
}
Parser/Php8.php000064400000541135151520657540007353 0ustar00<?php declare(strict_types=1);

namespace PhpParser\Parser;

use PhpParser\Error;
use PhpParser\Modifiers;
use PhpParser\Node;
use PhpParser\Node\Expr;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;

/* This is an automatically GENERATED file, which should not be manually edited.
 * Instead edit one of the following:
 *  * the grammar file grammar/php.y
 *  * the skeleton file grammar/parser.template
 *  * the preprocessing script grammar/rebuildParsers.php
 */
class Php8 extends \PhpParser\ParserAbstract
{
    public const YYERRTOK = 256;
    public const T_THROW = 257;
    public const T_INCLUDE = 258;
    public const T_INCLUDE_ONCE = 259;
    public const T_EVAL = 260;
    public const T_REQUIRE = 261;
    public const T_REQUIRE_ONCE = 262;
    public const T_LOGICAL_OR = 263;
    public const T_LOGICAL_XOR = 264;
    public const T_LOGICAL_AND = 265;
    public const T_PRINT = 266;
    public const T_YIELD = 267;
    public const T_DOUBLE_ARROW = 268;
    public const T_YIELD_FROM = 269;
    public const T_PLUS_EQUAL = 270;
    public const T_MINUS_EQUAL = 271;
    public const T_MUL_EQUAL = 272;
    public const T_DIV_EQUAL = 273;
    public const T_CONCAT_EQUAL = 274;
    public const T_MOD_EQUAL = 275;
    public const T_AND_EQUAL = 276;
    public const T_OR_EQUAL = 277;
    public const T_XOR_EQUAL = 278;
    public const T_SL_EQUAL = 279;
    public const T_SR_EQUAL = 280;
    public const T_POW_EQUAL = 281;
    public const T_COALESCE_EQUAL = 282;
    public const T_COALESCE = 283;
    public const T_BOOLEAN_OR = 284;
    public const T_BOOLEAN_AND = 285;
    public const T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG = 286;
    public const T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG = 287;
    public const T_IS_EQUAL = 288;
    public const T_IS_NOT_EQUAL = 289;
    public const T_IS_IDENTICAL = 290;
    public const T_IS_NOT_IDENTICAL = 291;
    public const T_SPACESHIP = 292;
    public const T_IS_SMALLER_OR_EQUAL = 293;
    public const T_IS_GREATER_OR_EQUAL = 294;
    public const T_SL = 295;
    public const T_SR = 296;
    public const T_INSTANCEOF = 297;
    public const T_INC = 298;
    public const T_DEC = 299;
    public const T_INT_CAST = 300;
    public const T_DOUBLE_CAST = 301;
    public const T_STRING_CAST = 302;
    public const T_ARRAY_CAST = 303;
    public const T_OBJECT_CAST = 304;
    public const T_BOOL_CAST = 305;
    public const T_UNSET_CAST = 306;
    public const T_POW = 307;
    public const T_NEW = 308;
    public const T_CLONE = 309;
    public const T_EXIT = 310;
    public const T_IF = 311;
    public const T_ELSEIF = 312;
    public const T_ELSE = 313;
    public const T_ENDIF = 314;
    public const T_LNUMBER = 315;
    public const T_DNUMBER = 316;
    public const T_STRING = 317;
    public const T_STRING_VARNAME = 318;
    public const T_VARIABLE = 319;
    public const T_NUM_STRING = 320;
    public const T_INLINE_HTML = 321;
    public const T_ENCAPSED_AND_WHITESPACE = 322;
    public const T_CONSTANT_ENCAPSED_STRING = 323;
    public const T_ECHO = 324;
    public const T_DO = 325;
    public const T_WHILE = 326;
    public const T_ENDWHILE = 327;
    public const T_FOR = 328;
    public const T_ENDFOR = 329;
    public const T_FOREACH = 330;
    public const T_ENDFOREACH = 331;
    public const T_DECLARE = 332;
    public const T_ENDDECLARE = 333;
    public const T_AS = 334;
    public const T_SWITCH = 335;
    public const T_MATCH = 336;
    public const T_ENDSWITCH = 337;
    public const T_CASE = 338;
    public const T_DEFAULT = 339;
    public const T_BREAK = 340;
    public const T_CONTINUE = 341;
    public const T_GOTO = 342;
    public const T_FUNCTION = 343;
    public const T_FN = 344;
    public const T_CONST = 345;
    public const T_RETURN = 346;
    public const T_TRY = 347;
    public const T_CATCH = 348;
    public const T_FINALLY = 349;
    public const T_USE = 350;
    public const T_INSTEADOF = 351;
    public const T_GLOBAL = 352;
    public const T_STATIC = 353;
    public const T_ABSTRACT = 354;
    public const T_FINAL = 355;
    public const T_PRIVATE = 356;
    public const T_PROTECTED = 357;
    public const T_PUBLIC = 358;
    public const T_READONLY = 359;
    public const T_VAR = 360;
    public const T_UNSET = 361;
    public const T_ISSET = 362;
    public const T_EMPTY = 363;
    public const T_HALT_COMPILER = 364;
    public const T_CLASS = 365;
    public const T_TRAIT = 366;
    public const T_INTERFACE = 367;
    public const T_ENUM = 368;
    public const T_EXTENDS = 369;
    public const T_IMPLEMENTS = 370;
    public const T_OBJECT_OPERATOR = 371;
    public const T_NULLSAFE_OBJECT_OPERATOR = 372;
    public const T_LIST = 373;
    public const T_ARRAY = 374;
    public const T_CALLABLE = 375;
    public const T_CLASS_C = 376;
    public const T_TRAIT_C = 377;
    public const T_METHOD_C = 378;
    public const T_FUNC_C = 379;
    public const T_LINE = 380;
    public const T_FILE = 381;
    public const T_START_HEREDOC = 382;
    public const T_END_HEREDOC = 383;
    public const T_DOLLAR_OPEN_CURLY_BRACES = 384;
    public const T_CURLY_OPEN = 385;
    public const T_PAAMAYIM_NEKUDOTAYIM = 386;
    public const T_NAMESPACE = 387;
    public const T_NS_C = 388;
    public const T_DIR = 389;
    public const T_NS_SEPARATOR = 390;
    public const T_ELLIPSIS = 391;
    public const T_NAME_FULLY_QUALIFIED = 392;
    public const T_NAME_QUALIFIED = 393;
    public const T_NAME_RELATIVE = 394;
    public const T_ATTRIBUTE = 395;

    protected int $tokenToSymbolMapSize = 396;
    protected int $actionTableSize = 1257;
    protected int $gotoTableSize = 657;

    protected int $invalidSymbol = 168;
    protected int $errorSymbol = 1;
    protected int $defaultAction = -32766;
    protected int $unexpectedTokenRule = 32767;

    protected int $YY2TBLSTATE = 435;
    protected int $numNonLeafStates = 739;

    protected array $symbolToName = array(
        "EOF",
        "error",
        "T_THROW",
        "T_INCLUDE",
        "T_INCLUDE_ONCE",
        "T_EVAL",
        "T_REQUIRE",
        "T_REQUIRE_ONCE",
        "','",
        "T_LOGICAL_OR",
        "T_LOGICAL_XOR",
        "T_LOGICAL_AND",
        "T_PRINT",
        "T_YIELD",
        "T_DOUBLE_ARROW",
        "T_YIELD_FROM",
        "'='",
        "T_PLUS_EQUAL",
        "T_MINUS_EQUAL",
        "T_MUL_EQUAL",
        "T_DIV_EQUAL",
        "T_CONCAT_EQUAL",
        "T_MOD_EQUAL",
        "T_AND_EQUAL",
        "T_OR_EQUAL",
        "T_XOR_EQUAL",
        "T_SL_EQUAL",
        "T_SR_EQUAL",
        "T_POW_EQUAL",
        "T_COALESCE_EQUAL",
        "'?'",
        "':'",
        "T_COALESCE",
        "T_BOOLEAN_OR",
        "T_BOOLEAN_AND",
        "'|'",
        "'^'",
        "T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG",
        "T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG",
        "T_IS_EQUAL",
        "T_IS_NOT_EQUAL",
        "T_IS_IDENTICAL",
        "T_IS_NOT_IDENTICAL",
        "T_SPACESHIP",
        "'<'",
        "T_IS_SMALLER_OR_EQUAL",
        "'>'",
        "T_IS_GREATER_OR_EQUAL",
        "'.'",
        "T_SL",
        "T_SR",
        "'+'",
        "'-'",
        "'*'",
        "'/'",
        "'%'",
        "'!'",
        "T_INSTANCEOF",
        "'~'",
        "T_INC",
        "T_DEC",
        "T_INT_CAST",
        "T_DOUBLE_CAST",
        "T_STRING_CAST",
        "T_ARRAY_CAST",
        "T_OBJECT_CAST",
        "T_BOOL_CAST",
        "T_UNSET_CAST",
        "'@'",
        "T_POW",
        "'['",
        "T_NEW",
        "T_CLONE",
        "T_EXIT",
        "T_IF",
        "T_ELSEIF",
        "T_ELSE",
        "T_ENDIF",
        "T_LNUMBER",
        "T_DNUMBER",
        "T_STRING",
        "T_STRING_VARNAME",
        "T_VARIABLE",
        "T_NUM_STRING",
        "T_INLINE_HTML",
        "T_ENCAPSED_AND_WHITESPACE",
        "T_CONSTANT_ENCAPSED_STRING",
        "T_ECHO",
        "T_DO",
        "T_WHILE",
        "T_ENDWHILE",
        "T_FOR",
        "T_ENDFOR",
        "T_FOREACH",
        "T_ENDFOREACH",
        "T_DECLARE",
        "T_ENDDECLARE",
        "T_AS",
        "T_SWITCH",
        "T_MATCH",
        "T_ENDSWITCH",
        "T_CASE",
        "T_DEFAULT",
        "T_BREAK",
        "T_CONTINUE",
        "T_GOTO",
        "T_FUNCTION",
        "T_FN",
        "T_CONST",
        "T_RETURN",
        "T_TRY",
        "T_CATCH",
        "T_FINALLY",
        "T_USE",
        "T_INSTEADOF",
        "T_GLOBAL",
        "T_STATIC",
        "T_ABSTRACT",
        "T_FINAL",
        "T_PRIVATE",
        "T_PROTECTED",
        "T_PUBLIC",
        "T_READONLY",
        "T_VAR",
        "T_UNSET",
        "T_ISSET",
        "T_EMPTY",
        "T_HALT_COMPILER",
        "T_CLASS",
        "T_TRAIT",
        "T_INTERFACE",
        "T_ENUM",
        "T_EXTENDS",
        "T_IMPLEMENTS",
        "T_OBJECT_OPERATOR",
        "T_NULLSAFE_OBJECT_OPERATOR",
        "T_LIST",
        "T_ARRAY",
        "T_CALLABLE",
        "T_CLASS_C",
        "T_TRAIT_C",
        "T_METHOD_C",
        "T_FUNC_C",
        "T_LINE",
        "T_FILE",
        "T_START_HEREDOC",
        "T_END_HEREDOC",
        "T_DOLLAR_OPEN_CURLY_BRACES",
        "T_CURLY_OPEN",
        "T_PAAMAYIM_NEKUDOTAYIM",
        "T_NAMESPACE",
        "T_NS_C",
        "T_DIR",
        "T_NS_SEPARATOR",
        "T_ELLIPSIS",
        "T_NAME_FULLY_QUALIFIED",
        "T_NAME_QUALIFIED",
        "T_NAME_RELATIVE",
        "T_ATTRIBUTE",
        "';'",
        "']'",
        "'('",
        "')'",
        "'{'",
        "'}'",
        "'`'",
        "'\"'",
        "'$'"
    );

    protected array $tokenToSymbol = array(
            0,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,   56,  166,  168,  167,   55,  168,  168,
          161,  162,   53,   51,    8,   52,   48,   54,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,   31,  159,
           44,   16,   46,   30,   68,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,   70,  168,  160,   36,  168,  165,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  163,   35,  164,   58,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,  168,  168,  168,  168,
          168,  168,  168,  168,  168,  168,    1,    2,    3,    4,
            5,    6,    7,    9,   10,   11,   12,   13,   14,   15,
           17,   18,   19,   20,   21,   22,   23,   24,   25,   26,
           27,   28,   29,   32,   33,   34,   37,   38,   39,   40,
           41,   42,   43,   45,   47,   49,   50,   57,   59,   60,
           61,   62,   63,   64,   65,   66,   67,   69,   71,   72,
           73,   74,   75,   76,   77,   78,   79,   80,   81,   82,
           83,   84,   85,   86,   87,   88,   89,   90,   91,   92,
           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,
          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,
          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,
          123,  124,  125,  126,  127,  128,  129,  130,  131,  132,
          133,  134,  135,  136,  137,  138,  139,  140,  141,  142,
          143,  144,  145,  146,  147,  148,  149,  150,  151,  152,
          153,  154,  155,  156,  157,  158
    );

    protected array $action = array(
          133,  134,  135,  582,  136,  137,    0,  751,  752,  753,
          138,   38,  327,-32766,-32766,-32766,-32766,-32766,-32766,  837,
          826,-32767,-32767,-32767,-32767,  102,  103,  104, 1112, 1113,
         1114, 1111, 1110, 1109, 1115,  745,  744,-32766, 1027,-32766,
        -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,
        -32767, 1245,-32766,-32766, 1322,  754, 1112, 1113, 1114, 1111,
         1110, 1109, 1115,  459,  460,  461,    2,  990, 1306,  265,
          139,  404,  758,  759,  760,  761,  467,  468,  429,  835,
          606,  -16, 1341,   23,  292,  815,  762,  763,  764,  765,
          766,  767,  768,  769,  770,  771,  791,  583,  792,  793,
          794,  795,  783,  784,  345,  346,  786,  787,  772,  773,
          774,  776,  777,  778,  356,  818,  819,  820,  821,  822,
          584,  779,  780,  585,  586,  941,  803,  801,  802,  814,
          798,  799,  835,  826,  587,  588,  797,  589,  590,  591,
          592,  593,  594, -328,   36,  251,   35, -194,  800,  595,
          596, -193,  140,  -85,  133,  134,  135,  582,  136,  137,
         1060,  751,  752,  753,  138,   38,  129, -110, -110, -585,
        -32766, -585, -110,-32766,-32766,-32766,  241,  836, -110,  145,
          959,  960,-32766,-32766,-32766,  961, -594,-32766,  482,  745,
          744,  955, 1036, -594,-32766,  991,-32766,-32766,-32766,-32766,
        -32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766,  299,  754,
          831,   75,-32766,-32766,-32766,  291,  142,  326,  242,  -85,
          326,  382,  381,  265,  139,  404,  758,  759,  760,  761,
           82,  423,  429,-32766,  326,-32766,-32766,-32766,-32766,  815,
          762,  763,  764,  765,  766,  767,  768,  769,  770,  771,
          791,  583,  792,  793,  794,  795,  783,  784,  345,  346,
          786,  787,  772,  773,  774,  776,  777,  778,  356,  818,
          819,  820,  821,  822,  584,  779,  780,  585,  586,  254,
          803,  801,  802,  814,  798,  799,  832,  725,  587,  588,
          797,  589,  590,  591,  592,  593,  594, -328,   83,   84,
           85, -194,  800,  595,  596, -193,  149,  775,  746,  747,
          748,  749,  750,  151,  751,  752,  753,  788,  789,   37,
          483,   86,   87,   88,   89,   90,   91,   92,   93,   94,
           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,
          105,  106,  107,  108,  109, -594,  274, -594,-32766,-32766,
        -32766,-32766,-32766,-32766,  310, 1089,  127,  312,  110,  737,
         1326,   21,  754,-32766,-32766,-32766, -272, 1325,-32766,-32766,
         1088,-32766,-32766,-32766,-32766,-32766,  755,  756,  757,  758,
          759,  760,  761, 1104,-32766,  824,-32766,-32766, -545,  429,
         1036,  323,  815,  762,  763,  764,  765,  766,  767,  768,
          769,  770,  771,  791,  813,  792,  793,  794,  795,  783,
          784,  785,  812,  786,  787,  772,  773,  774,  776,  777,
          778,  817,  818,  819,  820,  821,  822,  823,  779,  780,
          781,  782, 1033,  803,  801,  802,  814,  798,  799,  745,
          744,  790,  796,  797,  804,  805,  807,  806,  808,  809,
          152,-32766, -545, -545, 1036,  800,  811,  810,   50,   51,
           52,  513,   53,   54, 1240, 1239, 1241, -545,   55,   56,
         -110,   57,-32766, 1090,  920, -110,  556, -110,  292, -551,
          339, -545,  306,  103,  104, -110, -110, -110, -110, -110,
         -110, -110, -110,  105,  106,  107,  108,  109, 1245,  274,
          380,  381, -591, -367,  715, -367,  340,   58,   59, -591,
          423,  110,   60,  370,   61,  248,  249,   62,   63,   64,
           65,   66,   67,   68,   69, -544,   28,  267,   70,  445,
          514,-32766,  374, -342, 1272, 1273,  515, 1278,  835,  862,
          389,  863, 1270,   42,   25,  516,  943,  517,  943,  518,
          920,  519,  299, 1036,  520,  521, 1266,  910,  441,   44,
           45,  446,  377,  376,-32766,   46,  522, 1023, 1022, 1021,
         1024,  368,  338,  391, 1238,    7,  291,  442, 1231,  835,
          524,  525,  526,  443, 1245,  357, 1036,  362,  834, -544,
         -544,  154,  528,  529,  444, 1259, 1260, 1261, 1262, 1256,
         1257,  298,-32766,-32766, -544, -548, 1059, 1263, 1258,  291,
         1236, 1240, 1239, 1241,  299,  841, -550,   71, -544,  656,
           26,  321,  322,  326, -153, -153, -153,  920,  612,  675,
          676, 1035,  922,  910,-32766,  286,  710,  835,  155, -153,
          828, -153,  862, -153,  863, -153,  150,  407,  156, 1240,
         1239, 1241,-32766,-32766,-32766,  375, 1351,  716,   75, 1352,
          158, -591,   33, -591,  326,  835,  959,  960,  -78, -548,
         -548,  523,  920,-32766,  378,  379,  896,  955, -110, -110,
         -110,   32,  111,  112,  113,  114,  115,  116,  117,  118,
          119,  120,  121,  122,  123,  745,  744,  -58, -548,  -57,
         -110, -110,  717,  745,  744, -110,  383,  384,  922, 1033,
          910, -110,  710, -153,  647,  648,  830,  124,  141,  125,
        -32766, 1033,  326,  712, 1150, 1152,   48,  130,  131,  144,
          159, 1036,-32766,  160,  161, -543,   28,  162, 1238,  920,
          163,  299,  920, 1036,   75,-32766,-32766,-32766,  835,-32766,
          326,-32766, 1270,-32766,  282,  910,-32766,  -87,  -84,  -78,
          -73,-32766,-32766,-32766,   -4,  920,  282,-32766,-32766,  720,
          -72,  -71,  727,-32766,  420,  -70,  -69,  -68,  -67,  -66,
          287,  286,-32766,  -65,  -46,  922,  745,  744, 1231,  710,
          300,  301, -546,  -18,  148, -302,  273,  283,  726, -543,
         -543,  729,  528,  529,  920, 1259, 1260, 1261, 1262, 1256,
         1257,  919,   74,  147, -543,  288,  293, 1263, 1258,  126,
         -298,  280,  910,-32766,  281,  910,  284,   73, -543, 1238,
          976,  690,  322,  326,  710,  285,-32766,-32766,-32766,  332,
        -32766,  274,-32766,  294,-32766,  937,  110,-32766,  910,  685,
          835, -543,-32766,-32766,-32766,  826, -546, -546,-32766,-32766,
          146,-32766,  -50,  701,-32766,  420,  703,  691,   20, 1119,
          375, -546,  436,-32766,  645, 1353, 1277,  297,  657,-32766,
         1279,  959,  960,  561,  956, -546,  523,  910,  692,  693,
          678,  527,  955, -110, -110, -110,  132,  922,  662,  663,
          922,  710,  464, -508,  710,-32766, 1240, 1239, 1241,  493,
          679, 1238,  282,  939,   10, -543, -543,   40,-32766,-32766,
        -32766,  731,-32766,  922,-32766,  307,-32766,  710,   -4,-32766,
         -543,  305,   41,  304,-32766,-32766,-32766,    0,    0,-32766,
        -32766,-32766,  920,    0, -543, 1238,-32766,  420,  311,    0,
          567,  299,-32766,-32766,-32766,-32766,-32766, -498,-32766,  897,
        -32766,    0,  922,-32766,    8,    0,  710,   24,-32766,-32766,
        -32766,-32766,  372,  610,-32766,-32766,  834, 1238,  734, -275,
        -32766,  420,  920,  735,-32766,-32766,-32766,  854,-32766,-32766,
        -32766,  901,-32766, 1000,  977,-32766,   49,  984,  974,  488,
        -32766,-32766,-32766,-32766,  985,  899,-32766,-32766,  972, 1238,
          574, 1093,-32766,  420, 1096, 1097,-32766,-32766,-32766, 1094,
        -32766,-32766,-32766, 1095,-32766,  910, 1101,-32766, 1267,  846,
         1292, 1310,-32766,-32766,-32766, 1344,  650,   34,-32766,-32766,
         -579, -250, -250, -250,-32766,  420, -578,  375, -577, -551,
           28,  267, -550,-32766, -549, -492,    1,   29,  959,  960,
          302,  303,  835,  523,   30,  910, 1270,   39,  896,  955,
         -110, -110, -110,   43,   47,  373,   72,   76,   77,   78,
           79, -249, -249, -249,   80,   81,  143,  375,  153,  128,
         -273,  157,  247,  328,  357,  358,  359,  360,  959,  960,
          922,  361, 1231,  523,  710, -250,  362,  363,  896,  955,
         -110, -110, -110,  364,  365,  366,  367,  529,   28, 1259,
         1260, 1261, 1262, 1256, 1257,  369,  437,  555, 1207, -272,
          835, 1263, 1258,   13, 1270,   14,-32766,   15,   16,   18,
          922,   73, 1238, 1348,  710, -249,  322,  326,  406,-32766,
        -32766,-32766,  484,-32766,  485,-32766,  492,-32766,  495,  496,
        -32766,  497,  498,  502,  503,-32766,-32766,-32766,  504,  511,
         1231,-32766,-32766,  572,  696, 1249, 1190,-32766,  420, 1268,
         1062, 1061, 1042, 1226, 1038,  529,-32766, 1259, 1260, 1261,
         1262, 1256, 1257, -277, -102,   12,   17,   27,  296, 1263,
         1258,  405,  603,  607,  636,  702, 1194, 1244, 1191,   73,
          320, 1323,    0,  371,  322,  326,  711,  714,  718,  719,
          721,  722,  723,  724,  728,    0,  713,    0, 1350,  857,
          856,  865,  949,  992,  864, 1349,  948,  946,  947,  950,
         1222,  930,  940,  928,  982,  983,  634, 1347, 1304, 1293,
         1311, 1320,    0,    0, 1271,    0,  326
    );

    protected array $actionCheck = array(
            2,    3,    4,    5,    6,    7,    0,    9,   10,   11,
           12,   13,   70,    9,   10,   11,    9,   10,   11,    1,
           80,   44,   45,   46,   47,   48,   49,   50,  116,  117,
          118,  119,  120,  121,  122,   37,   38,   30,    1,   32,
           33,   34,   35,   36,   37,   38,   39,   40,   41,   42,
           43,    1,    9,   10,    1,   57,  116,  117,  118,  119,
          120,  121,  122,  129,  130,  131,    8,   31,    1,   71,
           72,   73,   74,   75,   76,   77,  134,  135,   80,   82,
            1,   31,   85,    8,   30,   87,   88,   89,   90,   91,
           92,   93,   94,   95,   96,   97,   98,   99,  100,  101,
          102,  103,  104,  105,  106,  107,  108,  109,  110,  111,
          112,  113,  114,  115,  116,  117,  118,  119,  120,  121,
          122,  123,  124,  125,  126,    1,  128,  129,  130,  131,
          132,  133,   82,   80,  136,  137,  138,  139,  140,  141,
          142,  143,  144,    8,  147,  148,    8,    8,  150,  151,
          152,    8,  154,   31,    2,    3,    4,    5,    6,    7,
          162,    9,   10,   11,   12,   13,    8,  117,  118,  160,
          116,  162,  122,    9,   10,   11,   97,  159,  128,    8,
          117,  118,    9,   10,   11,  122,    1,  137,   31,   37,
           38,  128,  138,    8,   30,  159,   32,   33,   34,   35,
           36,   37,   38,   30,    9,   32,   33,   34,  158,   57,
           80,  161,    9,   10,   11,  161,  163,  167,   14,   97,
          167,  106,  107,   71,   72,   73,   74,   75,   76,   77,
          163,  116,   80,   30,  167,   32,   33,   34,   35,   87,
           88,   89,   90,   91,   92,   93,   94,   95,   96,   97,
           98,   99,  100,  101,  102,  103,  104,  105,  106,  107,
          108,  109,  110,  111,  112,  113,  114,  115,  116,  117,
          118,  119,  120,  121,  122,  123,  124,  125,  126,    8,
          128,  129,  130,  131,  132,  133,  156,  163,  136,  137,
          138,  139,  140,  141,  142,  143,  144,  162,    9,   10,
           11,  162,  150,  151,  152,  162,  154,    2,    3,    4,
            5,    6,    7,   14,    9,   10,   11,   12,   13,   30,
          163,   32,   33,   34,   35,   36,   37,   38,   39,   40,
           41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
           51,   52,   53,   54,   55,  160,   57,  162,    9,   10,
           11,    9,   10,   11,    8,  159,   14,    8,   69,  163,
            1,  101,   57,    9,   10,   11,  162,    8,  116,   30,
            1,   32,   33,   34,   35,   36,   71,   72,   73,   74,
           75,   76,   77,  123,   30,   80,   32,   33,   70,   80,
          138,    8,   87,   88,   89,   90,   91,   92,   93,   94,
           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,
          105,  106,  107,  108,  109,  110,  111,  112,  113,  114,
          115,  116,  117,  118,  119,  120,  121,  122,  123,  124,
          125,  126,  116,  128,  129,  130,  131,  132,  133,   37,
           38,  136,  137,  138,  139,  140,  141,  142,  143,  144,
           14,  116,  134,  135,  138,  150,  151,  152,    2,    3,
            4,    5,    6,    7,  155,  156,  157,  149,   12,   13,
          101,   15,  137,  164,    1,  106,   85,  108,   30,  161,
            8,  163,  113,   49,   50,  116,  117,  118,  119,  120,
          121,  122,  123,   51,   52,   53,   54,   55,    1,   57,
          106,  107,    1,  106,   31,  108,    8,   51,   52,    8,
          116,   69,   56,    8,   58,   59,   60,   61,   62,   63,
           64,   65,   66,   67,   68,   70,   70,   71,   72,   73,
           74,  116,    8,  164,   78,   79,   80,  146,   82,  106,
            8,  108,   86,   87,   88,   89,  122,   91,  122,   93,
            1,   95,  158,  138,   98,   99,    1,   84,    8,  103,
          104,  105,  106,  107,  116,  109,  110,  119,  120,  121,
          122,  115,  116,  106,   80,  108,  161,    8,  122,   82,
          124,  125,  126,    8,    1,  161,  138,  161,  155,  134,
          135,   14,  136,  137,    8,  139,  140,  141,  142,  143,
          144,  145,   51,   52,  149,   70,    1,  151,  152,  161,
          116,  155,  156,  157,  158,    8,  161,  161,  163,   75,
           76,  165,  166,  167,   75,   76,   77,    1,   52,   75,
           76,  137,  159,   84,  137,   30,  163,   82,   14,   90,
           80,   92,  106,   94,  108,   96,  101,  102,   14,  155,
          156,  157,    9,   10,   11,  106,   80,   31,  161,   83,
           14,  160,   14,  162,  167,   82,  117,  118,   16,  134,
          135,  122,    1,   30,  106,  107,  127,  128,  129,  130,
          131,   16,   17,   18,   19,   20,   21,   22,   23,   24,
           25,   26,   27,   28,   29,   37,   38,   16,  163,   16,
          117,  118,   31,   37,   38,  122,  106,  107,  159,  116,
           84,  128,  163,  164,  111,  112,  156,   16,  163,   16,
          137,  116,  167,  163,   59,   60,   70,   16,   16,   16,
           16,  138,   74,   16,   16,   70,   70,   16,   80,    1,
           16,  158,    1,  138,  161,   87,   88,   89,   82,   91,
          167,   93,   86,   95,  161,   84,   98,   31,   31,   31,
           31,  103,  104,  105,    0,    1,  161,  109,  110,   31,
           31,   31,   31,  115,  116,   31,   31,   31,   31,   31,
           37,   30,  124,   31,   31,  159,   37,   38,  122,  163,
          134,  135,   70,   31,   31,   35,   31,   31,   31,  134,
          135,   31,  136,  137,    1,  139,  140,  141,  142,  143,
          144,   31,  154,   31,  149,   37,   37,  151,  152,  163,
           35,   35,   84,   74,   35,   84,   35,  161,  163,   80,
          159,   80,  166,  167,  163,   35,   87,   88,   89,   35,
           91,   57,   93,   37,   95,   38,   69,   98,   84,   77,
           82,   70,  103,  104,  105,   80,  134,  135,  109,  110,
           70,   85,   31,   80,  115,  116,   92,  116,   97,   82,
          106,  149,  108,  124,  113,   83,  146,  113,   90,  137,
          146,  117,  118,   89,  128,  163,  122,   84,  137,  138,
           94,  127,  128,  129,  130,  131,   31,  159,   96,  100,
          159,  163,   97,  149,  163,   74,  155,  156,  157,   97,
          100,   80,  161,  154,  150,  134,  135,  159,   87,   88,
           89,  164,   91,  159,   93,  114,   95,  163,  164,   98,
          149,  133,  159,  132,  103,  104,  105,   -1,   -1,   74,
          109,  110,    1,   -1,  163,   80,  115,  116,  132,   -1,
          153,  158,   87,   88,   89,  124,   91,  149,   93,  164,
           95,   -1,  159,   98,  149,   -1,  163,  149,  103,  104,
          105,   74,  149,  153,  109,  110,  155,   80,  159,  162,
          115,  116,    1,  159,   87,   88,   89,  159,   91,  124,
           93,  159,   95,  159,  159,   98,   70,  159,  159,  102,
          103,  104,  105,   74,  159,  159,  109,  110,  159,   80,
           81,  159,  115,  116,  159,  159,   87,   88,   89,  159,
           91,  124,   93,  159,   95,   84,  159,   98,  160,  160,
          160,  160,  103,  104,  105,  160,  160,  163,  109,  110,
          161,  100,  101,  102,  115,  116,  161,  106,  161,  161,
           70,   71,  161,  124,  161,  161,  161,  161,  117,  118,
          134,  135,   82,  122,  161,   84,   86,  161,  127,  128,
          129,  130,  131,  161,  161,  149,  161,  161,  161,  161,
          161,  100,  101,  102,  161,  161,  161,  106,  161,  163,
          162,  161,  161,  161,  161,  161,  161,  161,  117,  118,
          159,  161,  122,  122,  163,  164,  161,  161,  127,  128,
          129,  130,  131,  161,  161,  161,  161,  137,   70,  139,
          140,  141,  142,  143,  144,  161,  161,  161,  165,  162,
           82,  151,  152,  162,   86,  162,   74,  162,  162,  162,
          159,  161,   80,  164,  163,  164,  166,  167,  162,   87,
           88,   89,  162,   91,  162,   93,  162,   95,  162,  162,
           98,  162,  162,  162,  162,  103,  104,  105,  162,  162,
          122,  109,  110,  162,  162,  162,  162,  115,  116,  162,
          162,  162,  162,  162,  162,  137,  124,  139,  140,  141,
          142,  143,  144,  162,  162,  162,  162,  162,  162,  151,
          152,  162,  162,  162,  162,  162,  162,  162,  162,  161,
          163,  162,   -1,  163,  166,  167,  163,  163,  163,  163,
          163,  163,  163,  163,  163,   -1,  163,   -1,  164,  164,
          164,  164,  164,  164,  164,  164,  164,  164,  164,  164,
          164,  164,  164,  164,  164,  164,  164,  164,  164,  164,
          164,  164,   -1,   -1,  166,   -1,  167
    );

    protected array $actionBase = array(
            0,   -2,  152,  549,  764,  941,  981,  751,  555,  309,
          560,  864,  626,  738,  738,  741,  738,  473,  671,  783,
          -60,  305,  305,  783,  305,  803,  803,  803,  658,  658,
          658,  658,  749,  749,  897,  897,  929,  865,  831, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062, 1062,
         1062, 1062, 1062, 1062,   18,   36,   79,  648, 1036, 1044,
         1040, 1045, 1034, 1033, 1039, 1041, 1046, 1083, 1084,  782,
         1085, 1086, 1082, 1087, 1042,  876, 1035, 1043,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  195,  342,   43,    4,    4,
            4,    4,    4,    4,    4,    4,    4,    4,    4,    4,
            4,    4,    4,    4,    4,    4,    4,    4,  643,  643,
          643,  666,  666,  354,  173,  980,  203, 1048, 1048, 1048,
         1048, 1048, 1048, 1048, 1048, 1048,  665,  339,  164,  164,
            7,    7,    7,    7,    7,   50,  369,  583,  -23,  -23,
          -23,  -23,  448,  605,  497,  260,  397,  434,   54,  394,
          593,  593,  316,  316,  415,  415,  316,  316,  316,  442,
          442,  252,  252,  252,  252,  318,  455,  433,  391,  742,
           53,   53,   53,   53,  742,  742,  742,  742,  734, 1088,
          742,  742,  742,  722,  781,  781,  926,  551,  551,  781,
          536,   -3,   -3,  536,   63,   -3,   67,  576,  335,  756,
          115,    9,  335,  535,  656,  501,  185,  821,  568,  821,
         1032,  424,  776,  776,  426,  753,  729,  867, 1063, 1049,
          799, 1080,  810, 1081,  -66,  -58,  728, 1031, 1031, 1031,
         1031, 1031, 1031, 1031, 1031, 1031, 1031, 1031, 1089,  402,
         1032,  130, 1089, 1089, 1089,  402,  402,  402,  402,  402,
          402,  402,  402,  402,  402,  603,  130,  544,  554,  130,
          804,  402,   18,  808,   18,   18,   18,   18,   18,   18,
           18,   18,   18,   18,  762,  157,   18,   36,  124,  124,
          196,   37,  124,  124,  124,  124,   18,   18,   18,   18,
          568,  784,  797,  600,  820,  143,  784,  784,  784,  122,
          135,  204,  139,  760,  785,  467,  775,  775,  787,  895,
          895,  775,  768,  775,  787,  913,  775,  775,  895,  895,
          793,  158,  550,  472,  524,  569,  895,  346,  775,  775,
          775,  775,  816,  575,  775,  271,  171,  775,  775,  816,
          801,  766,   58,  798,  895,  895,  895,  816,  505,  798,
          798,  798,  819,  824,  761,  765,  383,  349,  607,  138,
          807,  765,  765,  775,  532,  761,  765,  761,  765,  759,
          765,  765,  765,  761,  765,  768,  498,  765,  714,  586,
           75,  765,    6,  915,  916,  726,  917,  906,  918,  965,
          919,  923, 1053,  894,  931,  912,  924,  966,  903,  896,
          780,  701,  703,  815,  754,  893,  777,  777,  777,  888,
          777,  777,  777,  777,  777,  777,  777,  777,  701,  868,
          823,  794,  934,  711,  712, 1011,  730,  795,  963,  933,
         1013,  925,  758,  713,  977,  935,  757, 1047,  936,  940,
          986, 1014,  828, 1017,  979,  790, 1064, 1065,  869,  946,
         1054,  777,  915,  923,  727,  912,  924,  903,  896,  752,
          748,  746,  747,  745,  744,  739,  740,  763, 1018,  887,
          879,  870,  945,  891,  701,  871,  971,  874,  990,  992,
         1050,  805,  792,  875, 1066,  952,  953,  954, 1055, 1019,
         1056,  773,  973,  817,  994,  812, 1067,  996,  997,  999,
         1000, 1057, 1068, 1058,  885, 1059,  832,  788,  928,  802,
         1069,  299,  791,  800,  806,  964,  436,  932, 1060, 1070,
         1071, 1001, 1002, 1006, 1072, 1073,  927,  834,  975,  796,
          976,  967,  835,  838,  577,  779, 1020,  786,  789,  778,
          624,  634, 1074, 1075, 1076,  930,  767,  772,  839,  845,
         1021,  743, 1022, 1077,  646,  846,  717, 1078, 1012,  718,
          721,  652,  683,  681,  724,  774, 1061,  818,  811,  771,
          955,  721,  770,  849, 1079,  852,  855,  856, 1007,  860,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
          456,  456,  456,  456,  456,  456,  305,  305,  305,  305,
          305,  456,  456,  456,  456,  456,  456,  456,  305,  305,
            0,    0,  305,    0,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  456,  456,  456,  456,  456,  456,  456,
          456,  456,  456,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          289,  289,  289,  289,  289,  289,  289,  289,  289,  289,
          494,  494,  289,  289,  494,  289,  494,  494,  494,  494,
          494,  494,  494,  494,  494,    0,  289,  289,  289,  289,
          289,  289,  289,  289,  494,  793,  494,  442,  442,  442,
          442,  494,  494,  494,  -88,  -88,  442,  494,   63,  494,
          494,  494,  494,  494,  494,  494,  494,  494,    0,    0,
          494,  494,  494,  494,    0,    0,  130,   -3,  494,  768,
          768,  768,  768,  494,  494,  494,  494,   -3,   -3,  494,
          494,  494,    0,    0,    0,    0,  442,  442,    0,  130,
            0,    0,  130,    0,    0,  768,  768,  494,   63,  793,
          359,  494,    0,    0,    0,    0,  130,  768,  130,  402,
          775,   -3,   -3,  775,  402,  402,  124,   18,  359,  545,
          545,  545,  545,    0,    0,  568,  793,  793,  793,  793,
          793,  793,  793,  793,  793,  793,  793,  768,    0,  793,
            0,  768,  768,  768,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,  768,
            0,    0,  895,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,  913,    0,    0,    0,    0,    0,    0,
          768,    0,    0,    0,    0,    0,    0,    0,    0,    0,
          777,  805,    0,  805,    0,  777,  777,  777,    0,    0,
            0,    0,  779,  743
    );

    protected array $actionDefault = array(
            3,32767,  102,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,  100,32767,32767,32767,32767,  597,  597,
          597,  597,32767,32767,  254,  102,32767,32767,  470,  387,
          387,  387,32767,32767,  541,  541,  541,  541,  541,  541,
        32767,32767,32767,32767,32767,32767,  470,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,  100,
        32767,32767,32767,   36,    7,    8,   10,   11,   49,   17,
          324,32767,32767,32767,32767,  102,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,  590,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,  474,  453,
          454,  456,  457,  386,  542,  596,  327,  593,  385,  145,
          339,  329,  242,  330,  258,  475,  259,  476,  479,  480,
          215,  287,  382,  149,  150,  417,  471,  419,  469,  473,
          418,  392,  398,  399,  400,  401,  402,  403,  404,  405,
          406,  407,  408,  409,  410,  390,  391,  472,  450,  449,
          448,32767,32767,  415,  416,32767,  420,32767,32767,32767,
        32767,32767,32767,32767,  102,32767,  389,  423,  421,  422,
          439,  440,  437,  438,  441,32767,32767,32767,  442,  443,
          444,  445,  316,32767,32767,  366,  364,  424,  316,  111,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,  430,
          431,32767,32767,32767,32767,  535,  447,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
          102,32767,  100,  537,  412,  414,  504,  425,  426,  393,
        32767,  511,32767,  102,32767,  513,32767,32767,32767,32767,
        32767,32767,32767,  536,32767,  543,  543,32767,  497,  100,
          195,32767,32767,  512,32767,  195,  195,32767,32767,32767,
        32767,32767,32767,32767,32767,  604,  497,  110,  110,  110,
          110,  110,  110,  110,  110,  110,  110,  110,32767,  195,
          110,32767,32767,32767,  100,  195,  195,  195,  195,  195,
          195,  195,  195,  195,  195,  190,32767,  268,  270,  102,
          558,  195,32767,  516,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,  509,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
          497,  435,  138,32767,  138,  543,  427,  428,  429,  499,
          543,  543,  543,  312,  289,32767,32767,32767,32767,  514,
          514,  100,  100,  100,  100,  509,32767,32767,32767,32767,
          111,   99,   99,   99,   99,   99,  103,  101,32767,32767,
        32767,32767,  223,   99,32767,  101,  101,32767,32767,  223,
          225,  212,  101,  227,32767,  562,  563,  223,  101,  227,
          227,  227,  247,  247,  486,  318,  101,   99,  101,  101,
          197,  318,  318,32767,  101,  486,  318,  486,  318,  199,
          318,  318,  318,  486,  318,32767,  101,  318,  214,   99,
           99,  318,32767,32767,32767,  499,32767,32767,32767,32767,
        32767,32767,32767,  222,32767,32767,32767,32767,32767,32767,
        32767,32767,  530,32767,  547,  560,  433,  434,  436,  545,
          458,  459,  460,  461,  462,  463,  464,  466,  592,32767,
          503,32767,32767,32767,  338,32767,  602,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,  603,32767,  543,32767,32767,32767,
        32767,  432,    9,   74,  492,   42,   43,   51,   57,  520,
          521,  522,  523,  517,  518,  524,  519,32767,32767,  525,
          568,32767,32767,  544,  595,32767,32767,32767,32767,32767,
        32767,  138,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,  530,32767,  136,32767,32767,32767,32767,
        32767,32767,32767,32767,  526,32767,32767,32767,  543,32767,
        32767,32767,32767,  314,  311,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,  543,32767,32767,32767,32767,32767,  291,32767,  308,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
        32767,32767,32767,32767,32767,32767,  286,32767,32767,  381,
          499,  294,  296,  297,32767,32767,32767,32767,  360,32767,
        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,
          152,  152,    3,    3,  341,  152,  152,  152,  341,  341,
          152,  341,  341,  341,  152,  152,  152,  152,  152,  152,
          280,  185,  262,  265,  247,  247,  152,  352,  152
    );

    protected array $goto = array(
          196,  196, 1034, 1065,  697,  431,  661,  621,  658,  319,
          706,  425,  314,  315,  335,  576,  430,  336,  432,  638,
          654,  655,  852,  672,  673,  674,  853,  167,  167,  167,
          167,  221,  197,  193,  193,  177,  179,  216,  193,  193,
          193,  193,  193,  194,  194,  194,  194,  194,  194,  188,
          189,  190,  191,  192,  218,  216,  219,  536,  537,  421,
          538,  540,  541,  542,  543,  544,  545,  546,  547, 1136,
          168,  169,  170,  195,  171,  172,  173,  166,  174,  175,
          176,  178,  215,  217,  220,  238,  243,  244,  246,  257,
          258,  259,  260,  261,  262,  263,  264,  268,  269,  270,
          271,  277,  289,  290,  317,  318,  426,  427,  428,  581,
          222,  223,  224,  225,  226,  227,  228,  229,  230,  231,
          232,  233,  234,  235,  236,  180,  237,  181,  198,  199,
          200,  239,  188,  189,  190,  191,  192,  218, 1136,  201,
          182,  183,  184,  202,  198,  185,  240,  203,  201,  165,
          204,  205,  186,  206,  207,  208,  187,  209,  210,  211,
          212,  213,  214,  855, 1232,  975,  279,  279,  279,  279,
          623,  623,  419,  351, 1269,  600, 1269, 1269, 1269, 1269,
         1269, 1269, 1269, 1269, 1269, 1287, 1287,  599, 1100, 1287,
          709, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287, 1287,
          508,  700,  827, 1098,  458,  559,  552,  860,  833,  909,
          904,  905,  918,  861,  906,  858,  907,  908,  859, 1233,
         1234,  912,  500,  886,  501,  252,  252,  843, 1107, 1108,
          507, 1087, 1082, 1083, 1084,  341,  552,  559,  568,  569,
          344,  579,  602,  616,  617, 1235, 1295, 1296,  833,  440,
          833,   22,  250,  250,  250,  250,  245,  253,  694,  573,
         1237,  829, 1237,  893,  851,  893,  893, 1034, 1034, 1237,
          694,  349,  342, 1034,  694, 1034, 1034, 1034, 1034, 1034,
         1034, 1034, 1034, 1034,  848, 1327, 1034, 1034, 1034, 1034,
         1319, 1319, 1319, 1319, 1237,  343,  342, 1040, 1039, 1237,
         1237, 1237, 1237,  868,  996, 1237, 1237, 1237,  913,  355,
          914,  354,  354,  354,  354,  466,  466,  479,  880,  355,
          355,  867,  394,  926,  466,  481,  571,  927,  967,  410,
          705,  942,  355,  355,  942,  848,  355,  660, 1354,  609,
          624,  627,  628,  629,  630,  651,  652,  653,  708,  554,
         1133, 1285, 1285,  355,  355, 1285, 1058, 1285, 1285, 1285,
         1285, 1285, 1285, 1285, 1285, 1285,  539,  539, 1185,  424,
          539,  611,  539,  539,  539,  539,  539,  539,  539,  539,
          539,  566,  682, 1337, 1337,  733,  637,  639, 1043, 1044,
          659,  476, 1312, 1313,  683,  687, 1010,  695,  704, 1006,
         1337, 1298,  438,  408,  409,  631,  633,  635,  670,    5,
          671,    6,  412,  413,  414,  337,  684, 1340, 1340,  415,
          325,  309,  686,  347,  352,  353,  553,  563,  450,  450,
          450,  553, 1309,  563, 1309,  666,  397,  462,  845, 1314,
         1315, 1309,  548,  548,  548,  548,  873,  604,  469,  580,
          470,  471,  403,  554,  878,  848,  958, 1345, 1346,  577,
          614,  870,  550,  615,  550,  255,  255, 1321, 1321, 1321,
         1321,  550,  999, 1018,  477,  971, 1228,  732,  736,  881,
          869, 1070, 1074,  876,  882,  551, 1008, 1003, 1071, 1075,
          978,  980,    0, 1305, 1118,    0,  456,    0,    0,    0,
            0,  969,  969,  969,  969,    0,    0,  456,  963,  970,
            0,    0,    0,    0,  968,    0, 1230,    0,    0,    0,
          450,  450,  450,  450,  450,  450,  450,  450,  450,  450,
          450,  931, 1123,  450,    0, 1073, 1116,  885,  619, 1307,
         1307, 1073, 1216,  944, 1015,  433, 1217, 1220,  945, 1221,
            0,  433,  872,    0,  664,  994,    0, 1041, 1041,    0,
          866,    0,    0,    0,  665, 1052, 1048, 1049,    0,    0,
            0,    0, 1227,  324,  275,  324, 1037, 1037,  681,  952,
            0,    0, 1029, 1045, 1046,  396,  399,  560,  601,  605,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,    0, 1013, 1013
    );

    protected array $gotoCheck = array(
           42,   42,   73,  127,   73,   66,   66,   56,   56,   66,
            9,   66,   66,   66,   66,   66,   66,   66,   66,   66,
           86,   86,   26,   86,   86,   86,   27,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   15,   20,   49,   23,   23,   23,   23,
          108,  108,   43,   97,  108,  130,  108,  108,  108,  108,
          108,  108,  108,  108,  108,  170,  170,    8,    8,  170,
            8,  170,  170,  170,  170,  170,  170,  170,  170,  170,
            8,    8,    6,    8,   83,   76,   76,   15,   12,   15,
           15,   15,   15,   15,   15,   15,   15,   15,   15,   20,
           20,   15,  155,   45,  155,    5,    5,   20,  144,  144,
          155,   15,   15,   15,   15,   76,   76,   76,   76,   76,
           76,   76,   76,   76,   76,   20,   20,   20,   12,   83,
           12,   76,    5,    5,    5,    5,    5,    5,    7,  172,
           73,    7,   73,   25,   25,   25,   25,   73,   73,   73,
            7,  179,  168,   73,    7,   73,   73,   73,   73,   73,
           73,   73,   73,   73,   22,  181,   73,   73,   73,   73,
            9,    9,    9,    9,   73,  168,  168,  118,  118,   73,
           73,   73,   73,   35,  103,   73,   73,   73,   65,   14,
           65,   24,   24,   24,   24,  149,  149,   84,   35,   14,
           14,   35,   62,   73,  149,   84,  104,   73,   93,   93,
           93,    9,   14,   14,    9,   22,   14,   64,   14,   81,
           81,   81,   81,   81,   81,   81,   81,   81,   81,   14,
          150,  171,  171,   14,   14,  171,  114,  171,  171,  171,
          171,  171,  171,  171,  171,  171,  173,  173,  151,   13,
          173,   13,  173,  173,  173,  173,  173,  173,  173,  173,
          173,   48,  116,  182,  182,   48,   48,   48,  119,  119,
           48,  176,  176,  176,   48,   48,   48,   48,   48,   48,
          182,   14,  113,   82,   82,   85,   85,   85,   82,   46,
           82,   46,   82,   82,   82,   29,   82,  182,  182,   82,
          169,  169,   14,   82,   97,   97,    9,    9,   23,   23,
           23,    9,  130,    9,  130,  120,    9,    9,   18,  178,
          178,  130,  107,  107,  107,  107,   39,  107,    9,    9,
            9,    9,   28,   14,    9,   22,   92,    9,    9,    2,
            2,   37,   19,   80,   19,    5,    5,  130,  130,  130,
          130,   19,   50,  110,  157,   50,  160,   50,   99,   16,
           16,   16,   16,    9,   41,   50,   50,   50,  129,  132,
           16,   96,   -1,  130,  147,   -1,   19,   -1,   -1,   -1,
           -1,   19,   19,   19,   19,   -1,   -1,   19,   19,   19,
           -1,   -1,   -1,   -1,   16,   -1,   14,   -1,   -1,   -1,
           23,   23,   23,   23,   23,   23,   23,   23,   23,   23,
           23,   17,   17,   23,   -1,  130,   16,   16,   17,  130,
          130,  130,   79,   79,   17,  117,   79,   79,   79,   79,
           -1,  117,   17,   -1,   17,   17,   -1,  117,  117,   -1,
           17,   -1,   -1,   -1,  117,  117,  117,  117,   -1,   -1,
           -1,   -1,   17,   24,   24,   24,   89,   89,   89,   89,
           -1,   -1,   89,   89,   89,   59,   59,   59,   59,   59,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
           -1,   -1,   -1,   -1,   -1,  107,  107
    );

    protected array $gotoBase = array(
            0,    0, -253,    0,    0,  224,  182,  251,  179,  -10,
            0,    0,  -89,   32,   11, -185,   27,   66,  128,  197,
         -229,    0,    5,  163,  308,  260,   18,   22,  115,  118,
            0,    0,    0,    0,    0,  -68,    0,  122,    0,  123,
            0,   43,   -1,  153,    0,  200, -327,    0, -330,  147,
          460,    0,    0,    0,    0,    0,  -33,    0,    0,  540,
            0,    0,  280,    0,   95,  294, -236,    0,    0,    0,
            0,    0,    0,   -5,    0,    0, -140,    0,    0,  134,
          119,  -19,  -88,  -75, -152,  -74, -698,    0,    0,  296,
            0,    0,  127,   23,    0,    0,   48, -310,    0,   71,
            0,    0,    0,  269,  283,    0,    0,  414,  -71,    0,
          103,    0,    0,  124,   83,    0,  100,  273,   17,  104,
          144,    0,    0,    0,    0,    0,    0,    1,    0,  114,
          167,    0,   47,    0,    0,    0,    0,    0,    0,    0,
            0,    0,    0,    0,  -47,    0,    0,   50,    0,  281,
          105,   94,    0,    0,    0, -273,    0,   34,    0,    0,
          107,    0,    0,    0,    0,    0,    0,    0,  -26,   99,
          -56,  110,  230,  125,    0,    0,   90,    0,   67,  241,
            0,  254,   75,    0,    0
    );

    protected array $gotoDefault = array(
        -32768,  512,  740,    4,  741,  935,  816,  825,  597,  530,
          707,  348,  625,  422, 1303,  911, 1122,  578,  844, 1246,
         1254,  457,  847,  330,  730,  923,  894,  895,  400,  386,
          392,  398,  649,  626,  494,  879,  453,  871,  486,  874,
          452,  883,  164,  418,  510,  887,    3,  890,  557,  921,
          973,  387,  898,  388,  677,  900,  562,  902,  903,  395,
          401,  402, 1127,  570,  622,  915,  256,  564,  916,  385,
          917,  925,  390,  393,  688,  465,  505,  499,  411, 1102,
          565,  608,  646,  447,  473,  620,  632,  618,  480,  434,
          416,  329,  957,  965,  487,  463,  979,  350,  987,  738,
         1135,  640,  489,  995,  641, 1002, 1005,  531,  532,  478,
         1017,  272, 1020,  490,   19,  667, 1031, 1032,  668,  642,
         1054,  643,  669,  644, 1056,  472,  598, 1064,  454, 1072,
         1291,  455, 1076,  266, 1079,  278,  417,  435, 1085, 1086,
            9, 1092,  698,  699,   11,  276,  509, 1117,  689,  451,
         1134,  439, 1204, 1206,  558,  491, 1224, 1223,  680,  506,
         1229,  448, 1294,  449,  533,  474,  316,  534, 1338,  308,
          333,  313,  549,  295,  334,  535,  475, 1300, 1308,  331,
           31, 1328, 1339,  575,  613
    );

    protected array $ruleToNonTerminal = array(
            0,    1,    3,    3,    2,    5,    5,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,
            6,    6,    6,    6,    6,    6,    6,    7,    7,    7,
            7,    7,    7,    7,    7,    8,    8,    9,   10,   11,
           11,   11,   12,   12,   13,   13,   14,   15,   15,   16,
           16,   17,   17,   18,   18,   21,   21,   22,   23,   23,
           24,   24,    4,    4,    4,    4,    4,    4,    4,    4,
            4,    4,    4,   29,   29,   30,   30,   32,   34,   34,
           28,   36,   36,   33,   38,   38,   35,   35,   37,   37,
           39,   39,   31,   40,   40,   41,   43,   44,   44,   45,
           45,   46,   46,   48,   47,   47,   47,   47,   49,   49,
           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,
           49,   49,   25,   25,   50,   69,   69,   72,   72,   71,
           70,   70,   63,   75,   75,   76,   76,   77,   77,   78,
           78,   79,   79,   80,   80,   26,   26,   27,   27,   27,
           27,   27,   88,   88,   90,   90,   83,   83,   91,   91,
           92,   92,   92,   84,   84,   87,   87,   85,   85,   93,
           94,   94,   57,   57,   65,   65,   68,   68,   68,   67,
           95,   95,   96,   58,   58,   58,   58,   97,   97,   98,
           98,   99,   99,  100,  101,  101,  102,  102,  103,  103,
           55,   55,   51,   51,  105,   53,   53,  106,   52,   52,
           54,   54,   64,   64,   64,   64,   81,   81,  109,  109,
          111,  111,  112,  112,  112,  112,  110,  110,  110,  114,
          114,  114,  114,   89,   89,  117,  117,  117,  118,  118,
          115,  115,  119,  119,  121,  121,  122,  122,  116,  123,
          123,  120,  124,  124,  124,  124,  113,  113,   82,   82,
           82,   20,   20,   20,  126,  125,  125,  127,  127,  127,
          127,   60,  128,  128,  129,   61,  131,  131,  132,  132,
          133,  133,   86,  134,  134,  134,  134,  134,  134,  134,
          139,  139,  140,  140,  141,  141,  141,  141,  141,  142,
          143,  143,  138,  138,  135,  135,  137,  137,  145,  145,
          144,  144,  144,  144,  144,  144,  144,  136,  146,  146,
          148,  147,  147,   62,  104,  149,  149,   56,   56,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,
           42,   42,   42,  156,  150,  150,  155,  155,  158,  159,
          159,  160,  161,  162,  162,  162,  162,   19,   19,   73,
           73,   73,   73,  151,  151,  151,  151,  164,  164,  152,
          152,  154,  154,  154,  157,  157,  170,  170,  170,  170,
          170,  170,  170,  170,  170,  171,  171,  171,  108,  173,
          173,  173,  173,  153,  153,  153,  153,  153,  153,  153,
          153,   59,   59,  167,  167,  167,  167,  174,  174,  163,
          163,  163,  175,  175,  175,  175,  175,  175,   74,   74,
           66,   66,   66,   66,  130,  130,  130,  130,  178,  177,
          166,  166,  166,  166,  166,  166,  166,  165,  165,  165,
          176,  176,  176,  176,  107,  172,  180,  180,  179,  179,
          181,  181,  181,  181,  181,  181,  181,  181,  169,  169,
          169,  169,  168,  183,  182,  182,  182,  182,  182,  182,
          182,  182,  184,  184,  184,  184
    );

    protected array $ruleToLength = array(
            1,    1,    2,    0,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    1,    1,    1,    1,    0,
            1,    0,    1,    1,    2,    1,    3,    4,    1,    2,
            0,    1,    1,    1,    1,    4,    3,    5,    4,    3,
            4,    2,    3,    1,    1,    7,    6,    2,    3,    1,
            2,    3,    1,    2,    3,    1,    1,    3,    1,    3,
            1,    2,    2,    3,    1,    3,    2,    3,    1,    3,
            3,    2,    0,    1,    1,    1,    1,    1,    3,    7,
           10,    5,    7,    9,    5,    3,    3,    3,    3,    3,
            3,    1,    2,    5,    7,    9,    6,    5,    6,    3,
            2,    1,    1,    1,    1,    0,    2,    1,    3,    8,
            0,    4,    2,    1,    3,    0,    1,    0,    1,    0,
            1,    3,    1,    1,    1,    8,    9,    7,    8,    7,
            6,    8,    0,    2,    0,    2,    1,    2,    1,    2,
            1,    1,    1,    0,    2,    0,    2,    0,    2,    2,
            1,    3,    1,    4,    1,    4,    1,    1,    4,    2,
            1,    3,    3,    3,    4,    4,    5,    0,    2,    4,
            3,    1,    1,    7,    0,    2,    1,    3,    3,    4,
            1,    4,    0,    2,    5,    0,    2,    6,    0,    2,
            0,    3,    1,    2,    1,    1,    2,    0,    1,    3,
            0,    2,    1,    1,    1,    1,    6,    8,    6,    1,
            2,    1,    1,    1,    1,    1,    1,    1,    1,    3,
            3,    3,    1,    3,    3,    3,    3,    3,    1,    3,
            3,    1,    1,    2,    1,    1,    0,    1,    0,    2,
            2,    2,    4,    3,    1,    1,    3,    1,    2,    2,
            3,    2,    3,    1,    1,    2,    3,    1,    1,    3,
            2,    0,    1,    5,    5,    6,   10,    3,    5,    1,
            1,    3,    0,    2,    4,    5,    4,    4,    4,    3,
            1,    1,    1,    1,    1,    1,    0,    1,    1,    2,
            1,    1,    1,    1,    1,    1,    1,    2,    1,    3,
            1,    1,    3,    2,    2,    3,    1,    0,    1,    1,
            3,    3,    3,    4,    4,    1,    1,    2,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
            3,    2,    2,    2,    2,    3,    3,    3,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,
            3,    3,    3,    2,    2,    2,    2,    3,    3,    3,
            3,    3,    3,    3,    3,    3,    3,    3,    5,    4,
            3,    4,    4,    2,    2,    4,    2,    2,    2,    2,
            2,    2,    2,    2,    2,    2,    2,    1,    3,    2,
            1,    2,    4,    2,    2,    8,    9,    8,    9,    9,
           10,    9,   10,    8,    3,    2,    0,    4,    2,    1,
            3,    2,    1,    2,    2,    2,    4,    1,    1,    1,
            1,    1,    1,    1,    1,    3,    1,    1,    1,    0,
            3,    0,    1,    1,    0,    1,    1,    1,    1,    1,
            1,    1,    1,    1,    1,    3,    5,    3,    3,    4,
            1,    1,    3,    1,    1,    1,    1,    1,    3,    2,
            3,    0,    1,    1,    3,    1,    1,    1,    1,    1,
            3,    1,    1,    4,    4,    1,    4,    4,    0,    1,
            1,    1,    3,    3,    1,    4,    2,    2,    1,    3,
            1,    4,    4,    3,    3,    3,    3,    1,    3,    1,
            1,    3,    1,    1,    4,    1,    1,    1,    3,    1,
            1,    2,    1,    3,    4,    3,    2,    0,    2,    2,
            1,    2,    1,    1,    1,    4,    3,    3,    3,    3,
            6,    3,    1,    1,    2,    1
    );

    protected function initReduceCallbacks(): void {
        $this->reduceCallbacks = [
            0 => null,
            1 => static function ($self, $stackPos) {
                 $self->semValue = $self->handleNamespaces($self->semStack[$stackPos-(1-1)]);
            },
            2 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;
            },
            3 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            4 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            5 => null,
            6 => null,
            7 => null,
            8 => null,
            9 => null,
            10 => null,
            11 => null,
            12 => null,
            13 => null,
            14 => null,
            15 => null,
            16 => null,
            17 => null,
            18 => null,
            19 => null,
            20 => null,
            21 => null,
            22 => null,
            23 => null,
            24 => null,
            25 => null,
            26 => null,
            27 => null,
            28 => null,
            29 => null,
            30 => null,
            31 => null,
            32 => null,
            33 => null,
            34 => null,
            35 => null,
            36 => null,
            37 => null,
            38 => null,
            39 => null,
            40 => null,
            41 => null,
            42 => null,
            43 => null,
            44 => null,
            45 => null,
            46 => null,
            47 => null,
            48 => null,
            49 => null,
            50 => null,
            51 => null,
            52 => null,
            53 => null,
            54 => null,
            55 => null,
            56 => null,
            57 => null,
            58 => null,
            59 => null,
            60 => null,
            61 => null,
            62 => null,
            63 => null,
            64 => null,
            65 => null,
            66 => null,
            67 => null,
            68 => null,
            69 => null,
            70 => null,
            71 => null,
            72 => null,
            73 => null,
            74 => null,
            75 => null,
            76 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; if ($self->semValue === "<?=") $self->emitError(new Error('Cannot use "<?=" as an identifier', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));
            },
            77 => null,
            78 => null,
            79 => null,
            80 => null,
            81 => null,
            82 => null,
            83 => null,
            84 => null,
            85 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            86 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            87 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            88 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            89 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            90 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            91 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            92 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            93 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            94 => null,
            95 => static function ($self, $stackPos) {
                 $self->semValue = new Name(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            96 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            97 => static function ($self, $stackPos) {
                 /* nothing */
            },
            98 => static function ($self, $stackPos) {
                 /* nothing */
            },
            99 => static function ($self, $stackPos) {
                 /* nothing */
            },
            100 => static function ($self, $stackPos) {
                 $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));
            },
            101 => null,
            102 => null,
            103 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Attribute($self->semStack[$stackPos-(1-1)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            104 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Attribute($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            105 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            106 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            107 => static function ($self, $stackPos) {
                 $self->semValue = new Node\AttributeGroup($self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            108 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            109 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            110 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            111 => null,
            112 => null,
            113 => null,
            114 => null,
            115 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            116 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos-(3-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_SEMICOLON);
            $self->checkNamespace($self->semValue);
            },
            117 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_($self->semStack[$stackPos-(5-2)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED);
            $self->checkNamespace($self->semValue);
            },
            118 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Namespace_(null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            $self->semValue->setAttribute('kind', Stmt\Namespace_::KIND_BRACED);
            $self->checkNamespace($self->semValue);
            },
            119 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Use_($self->semStack[$stackPos-(3-2)], Stmt\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            120 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Use_($self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            121 => null,
            122 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Const_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            123 => static function ($self, $stackPos) {
                 $self->semValue = Stmt\Use_::TYPE_FUNCTION;
            },
            124 => static function ($self, $stackPos) {
                 $self->semValue = Stmt\Use_::TYPE_CONSTANT;
            },
            125 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-6)], $self->semStack[$stackPos-(7-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            126 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\GroupUse($self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-5)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            127 => null,
            128 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            129 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            130 => null,
            131 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            132 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            133 => null,
            134 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            135 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            136 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(1-1));
            },
            137 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(3-3));
            },
            138 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(1-1)], null, Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(1-1));
            },
            139 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UseItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], Stmt\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->checkUseUse($self->semValue, $stackPos-(3-3));
            },
            140 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->semValue->type = Stmt\Use_::TYPE_NORMAL;
            },
            141 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)]; $self->semValue->type = $self->semStack[$stackPos-(2-1)];
            },
            142 => null,
            143 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            144 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            145 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            146 => null,
            147 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            148 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            149 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            150 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Const_(new Node\Identifier($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            151 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;
            },
            152 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            153 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            154 => null,
            155 => null,
            156 => null,
            157 => static function ($self, $stackPos) {
                 throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            158 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Block($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            159 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\If_($self->semStack[$stackPos-(7-3)], ['stmts' => $self->semStack[$stackPos-(7-5)], 'elseifs' => $self->semStack[$stackPos-(7-6)], 'else' => $self->semStack[$stackPos-(7-7)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            160 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\If_($self->semStack[$stackPos-(10-3)], ['stmts' => $self->semStack[$stackPos-(10-6)], 'elseifs' => $self->semStack[$stackPos-(10-7)], 'else' => $self->semStack[$stackPos-(10-8)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            161 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\While_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            162 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Do_($self->semStack[$stackPos-(7-5)], $self->semStack[$stackPos-(7-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            163 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\For_(['init' => $self->semStack[$stackPos-(9-3)], 'cond' => $self->semStack[$stackPos-(9-5)], 'loop' => $self->semStack[$stackPos-(9-7)], 'stmts' => $self->semStack[$stackPos-(9-9)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            164 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Switch_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            165 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Break_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            166 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Continue_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            167 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Return_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            168 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Global_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            169 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Static_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            170 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Echo_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            171 => static function ($self, $stackPos) {

        $self->semValue = new Stmt\InlineHTML($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
        $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos-(1-1)));

            },
            172 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Expression($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            173 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Unset_($self->semStack[$stackPos-(5-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            174 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-5)][0], ['keyVar' => null, 'byRef' => $self->semStack[$stackPos-(7-5)][1], 'stmts' => $self->semStack[$stackPos-(7-7)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            175 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(9-3)], $self->semStack[$stackPos-(9-7)][0], ['keyVar' => $self->semStack[$stackPos-(9-5)], 'byRef' => $self->semStack[$stackPos-(9-7)][1], 'stmts' => $self->semStack[$stackPos-(9-9)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            176 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Foreach_($self->semStack[$stackPos-(6-3)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(6-4)],  $self->tokenEndStack[$stackPos-(6-4)])), ['stmts' => $self->semStack[$stackPos-(6-6)]], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            177 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Declare_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            178 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TryCatch($self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-5)], $self->semStack[$stackPos-(6-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])); $self->checkTryCatch($self->semValue);
            },
            179 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Goto_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            180 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Label($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            181 => static function ($self, $stackPos) {
                 $self->semValue = null; /* means: no statement */
            },
            182 => null,
            183 => static function ($self, $stackPos) {
                 $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]);
            },
            184 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(1-1)] instanceof Stmt\Block) { $self->semValue = $self->semStack[$stackPos-(1-1)]->stmts; } else if ($self->semStack[$stackPos-(1-1)] === null) { $self->semValue = []; } else { $self->semValue = [$self->semStack[$stackPos-(1-1)]]; };
            },
            185 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            186 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            187 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            188 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            189 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Catch_($self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-7)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            190 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            191 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Finally_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            192 => null,
            193 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            194 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            195 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            196 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            197 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            198 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            199 => static function ($self, $stackPos) {
                 $self->semValue = false;
            },
            200 => static function ($self, $stackPos) {
                 $self->semValue = true;
            },
            201 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            202 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            203 => null,
            204 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            205 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Function_($self->semStack[$stackPos-(8-3)], ['byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-5)], 'returnType' => $self->semStack[$stackPos-(8-7)], 'stmts' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            206 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Function_($self->semStack[$stackPos-(9-4)], ['byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-6)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            207 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Class_($self->semStack[$stackPos-(7-2)], ['type' => $self->semStack[$stackPos-(7-1)], 'extends' => $self->semStack[$stackPos-(7-3)], 'implements' => $self->semStack[$stackPos-(7-4)], 'stmts' => $self->semStack[$stackPos-(7-6)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClass($self->semValue, $stackPos-(7-2));
            },
            208 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Class_($self->semStack[$stackPos-(8-3)], ['type' => $self->semStack[$stackPos-(8-2)], 'extends' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClass($self->semValue, $stackPos-(8-3));
            },
            209 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Interface_($self->semStack[$stackPos-(7-3)], ['extends' => $self->semStack[$stackPos-(7-4)], 'stmts' => $self->semStack[$stackPos-(7-6)], 'attrGroups' => $self->semStack[$stackPos-(7-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            $self->checkInterface($self->semValue, $stackPos-(7-3));
            },
            210 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Trait_($self->semStack[$stackPos-(6-3)], ['stmts' => $self->semStack[$stackPos-(6-5)], 'attrGroups' => $self->semStack[$stackPos-(6-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            211 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Enum_($self->semStack[$stackPos-(8-3)], ['scalarType' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            $self->checkEnum($self->semValue, $stackPos-(8-3));
            },
            212 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            213 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            214 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            215 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            216 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            217 => null,
            218 => null,
            219 => static function ($self, $stackPos) {
                 $self->checkClassModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            220 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::ABSTRACT;
            },
            221 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::FINAL;
            },
            222 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            223 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            224 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            225 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            226 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            227 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            228 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            229 => null,
            230 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            231 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            232 => null,
            233 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            234 => null,
            235 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            236 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(1-1)] instanceof Stmt\Block) { $self->semValue = $self->semStack[$stackPos-(1-1)]->stmts; } else if ($self->semStack[$stackPos-(1-1)] === null) { $self->semValue = []; } else { $self->semValue = [$self->semStack[$stackPos-(1-1)]]; };
            },
            237 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            238 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            239 => null,
            240 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            241 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            242 => static function ($self, $stackPos) {
                 $self->semValue = new Node\DeclareItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            243 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            244 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-3)];
            },
            245 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            246 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(5-3)];
            },
            247 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            248 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            249 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Case_($self->semStack[$stackPos-(4-2)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            250 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Case_(null, $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            251 => null,
            252 => null,
            253 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Match_($self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));
            },
            254 => static function ($self, $stackPos) {
                 $self->semValue = [];
            },
            255 => null,
            256 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            257 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            258 => static function ($self, $stackPos) {
                 $self->semValue = new Node\MatchArm($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            259 => static function ($self, $stackPos) {
                 $self->semValue = new Node\MatchArm(null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            260 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            261 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            262 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            263 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            264 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            265 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            266 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            267 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ElseIf_($self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-6)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);
            },
            268 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            269 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Else_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            270 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            271 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Else_($self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);
            },
            272 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);
            },
            273 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(2-2)], true);
            },
            274 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);
            },
            275 => static function ($self, $stackPos) {
                 $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos-(1-1)]), false);
            },
            276 => null,
            277 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            278 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            279 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            280 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            281 => static function ($self, $stackPos) {
                 $self->checkModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            282 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PUBLIC;
            },
            283 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PROTECTED;
            },
            284 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PRIVATE;
            },
            285 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            286 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param($self->semStack[$stackPos-(6-6)], null, $self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-4)], $self->semStack[$stackPos-(6-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-1)]);
            $self->checkParam($self->semValue);
            },
            287 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param($self->semStack[$stackPos-(8-6)], $self->semStack[$stackPos-(8-8)], $self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(8-2)], $self->semStack[$stackPos-(8-1)]);
            $self->checkParam($self->semValue);
            },
            288 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Param(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos])), null, $self->semStack[$stackPos-(6-3)], $self->semStack[$stackPos-(6-4)], $self->semStack[$stackPos-(6-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-1)]);
            },
            289 => null,
            290 => static function ($self, $stackPos) {
                 $self->semValue = new Node\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            291 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            292 => null,
            293 => null,
            294 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            295 => static function ($self, $stackPos) {
                 $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos-(1-1)]);
            },
            296 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            297 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            298 => null,
            299 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            300 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            301 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            302 => null,
            303 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            304 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            305 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            306 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            307 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            308 => static function ($self, $stackPos) {
                 $self->semValue = new Node\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            309 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            310 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            311 => static function ($self, $stackPos) {
                 $self->semValue = new Node\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            312 => null,
            313 => static function ($self, $stackPos) {
                 $self->semValue = new Node\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            314 => static function ($self, $stackPos) {
                 $self->semValue = new Node\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            315 => null,
            316 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            317 => null,
            318 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            319 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(2-2)];
            },
            320 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            321 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            322 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-2)];
            },
            323 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-2)]);
            },
            324 => static function ($self, $stackPos) {
                 $self->semValue = new Node\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            325 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            326 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            327 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(1-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            328 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(2-2)], true, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            329 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(2-2)], false, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            330 => static function ($self, $stackPos) {
                 $self->semValue = new Node\Arg($self->semStack[$stackPos-(3-3)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(3-1)]);
            },
            331 => null,
            332 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            333 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            334 => null,
            335 => null,
            336 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            337 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            338 => static function ($self, $stackPos) {
                 $self->semValue = new Node\StaticVar($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            339 => static function ($self, $stackPos) {
                 $self->semValue = new Node\StaticVar($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            340 => static function ($self, $stackPos) {
                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)]; } else { $self->semValue = $self->semStack[$stackPos-(2-1)]; }
            },
            341 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            342 => static function ($self, $stackPos) {
                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;
            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            343 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\Property($self->semStack[$stackPos-(5-2)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-1)]);
            $self->checkProperty($self->semValue, $stackPos-(5-2));
            },
            344 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(5-1)]);
            $self->checkClassConst($self->semValue, $stackPos-(5-2));
            },
            345 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassConst($self->semStack[$stackPos-(6-5)], $self->semStack[$stackPos-(6-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(6-1)], $self->semStack[$stackPos-(6-4)]);
            $self->checkClassConst($self->semValue, $stackPos-(6-2));
            },
            346 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\ClassMethod($self->semStack[$stackPos-(10-5)], ['type' => $self->semStack[$stackPos-(10-2)], 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-7)], 'returnType' => $self->semStack[$stackPos-(10-9)], 'stmts' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            $self->checkClassMethod($self->semValue, $stackPos-(10-2));
            },
            347 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUse($self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            348 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\EnumCase($self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            349 => static function ($self, $stackPos) {
                 $self->semValue = null; /* will be skipped */
            },
            350 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            351 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            352 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            353 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            354 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Precedence($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            355 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(5-1)][0], $self->semStack[$stackPos-(5-1)][1], $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            356 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], $self->semStack[$stackPos-(4-3)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            357 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            358 => static function ($self, $stackPos) {
                 $self->semValue = new Stmt\TraitUseAdaptation\Alias($self->semStack[$stackPos-(4-1)][0], $self->semStack[$stackPos-(4-1)][1], null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            359 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);
            },
            360 => null,
            361 => static function ($self, $stackPos) {
                 $self->semValue = array(null, $self->semStack[$stackPos-(1-1)]);
            },
            362 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            363 => null,
            364 => null,
            365 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            366 => static function ($self, $stackPos) {
                 $self->semValue = 0;
            },
            367 => null,
            368 => null,
            369 => static function ($self, $stackPos) {
                 $self->checkModifier($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $stackPos-(2-2)); $self->semValue = $self->semStack[$stackPos-(2-1)] | $self->semStack[$stackPos-(2-2)];
            },
            370 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PUBLIC;
            },
            371 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PROTECTED;
            },
            372 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::PRIVATE;
            },
            373 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::STATIC;
            },
            374 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::ABSTRACT;
            },
            375 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::FINAL;
            },
            376 => static function ($self, $stackPos) {
                 $self->semValue = Modifiers::READONLY;
            },
            377 => null,
            378 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            379 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            380 => static function ($self, $stackPos) {
                 $self->semValue = new Node\VarLikeIdentifier(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            381 => static function ($self, $stackPos) {
                 $self->semValue = new Node\PropertyItem($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            382 => static function ($self, $stackPos) {
                 $self->semValue = new Node\PropertyItem($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            383 => null,
            384 => null,
            385 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            386 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            387 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            388 => null,
            389 => null,
            390 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            391 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->fixupArrayDestructuring($self->semStack[$stackPos-(3-1)]), $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            392 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Assign($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            393 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignRef($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            394 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignRef($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            if (!$self->phpVersion->allowsAssignNewByReference()) {
                $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));
            }

            },
            395 => null,
            396 => null,
            397 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Clone_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            398 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Plus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            399 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Minus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            400 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Mul($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            401 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Div($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            402 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Concat($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            403 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Mod($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            404 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            405 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            406 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\BitwiseXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            407 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\ShiftLeft($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            408 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\ShiftRight($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            409 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Pow($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            410 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\AssignOp\Coalesce($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            411 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PostInc($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            412 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PreInc($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            413 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PostDec($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            414 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PreDec($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            415 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BooleanOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            416 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BooleanAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            417 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            418 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            419 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\LogicalXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            420 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseOr($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            421 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            422 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseAnd($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            423 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\BitwiseXor($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            424 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Concat($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            425 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Plus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            426 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Minus($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            427 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Mul($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            428 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Div($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            429 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Mod($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            430 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\ShiftLeft($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            431 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\ShiftRight($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            432 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Pow($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            433 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\UnaryPlus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            434 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\UnaryMinus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            435 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BooleanNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            436 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BitwiseNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            437 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Identical($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            438 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\NotIdentical($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            439 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Equal($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            440 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\NotEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            441 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Spaceship($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            442 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Smaller($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            443 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\SmallerOrEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            444 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Greater($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            445 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\GreaterOrEqual($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            446 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Instanceof_($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            447 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            448 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Ternary($self->semStack[$stackPos-(5-1)], $self->semStack[$stackPos-(5-3)], $self->semStack[$stackPos-(5-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            449 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Ternary($self->semStack[$stackPos-(4-1)], null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            450 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\BinaryOp\Coalesce($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            451 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Isset_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            452 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Empty_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            453 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            454 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_INCLUDE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            455 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Eval_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            456 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            457 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Include_($self->semStack[$stackPos-(2-2)], Expr\Include_::TYPE_REQUIRE_ONCE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            458 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Int_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            459 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
            $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos-(2-1)]);
            $self->semValue = new Expr\Cast\Double($self->semStack[$stackPos-(2-2)], $attrs);
            },
            460 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\String_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            461 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            462 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            463 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Bool_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            464 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Cast\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            465 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);
            $attrs['kind'] = strtolower($self->semStack[$stackPos-(2-1)]) === 'exit' ? Expr\Exit_::KIND_EXIT : Expr\Exit_::KIND_DIE;
            $self->semValue = new Expr\Exit_($self->semStack[$stackPos-(2-2)], $attrs);
            },
            466 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ErrorSuppress($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            467 => null,
            468 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ShellExec($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            469 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Print_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            470 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            471 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_($self->semStack[$stackPos-(2-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            472 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Yield_($self->semStack[$stackPos-(4-4)], $self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            473 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\YieldFrom($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            474 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Throw_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            475 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => false, 'byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-4)], 'returnType' => $self->semStack[$stackPos-(8-6)], 'expr' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            476 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => true, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'returnType' => $self->semStack[$stackPos-(9-7)], 'expr' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            477 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => false, 'byRef' => $self->semStack[$stackPos-(8-2)], 'params' => $self->semStack[$stackPos-(8-4)], 'uses' => $self->semStack[$stackPos-(8-6)], 'returnType' => $self->semStack[$stackPos-(8-7)], 'stmts' => $self->semStack[$stackPos-(8-8)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));
            },
            478 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => true, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'uses' => $self->semStack[$stackPos-(9-7)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => []], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            479 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => false, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'returnType' => $self->semStack[$stackPos-(9-7)], 'expr' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            480 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrowFunction(['static' => true, 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-6)], 'returnType' => $self->semStack[$stackPos-(10-8)], 'expr' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            481 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => false, 'byRef' => $self->semStack[$stackPos-(9-3)], 'params' => $self->semStack[$stackPos-(9-5)], 'uses' => $self->semStack[$stackPos-(9-7)], 'returnType' => $self->semStack[$stackPos-(9-8)], 'stmts' => $self->semStack[$stackPos-(9-9)], 'attrGroups' => $self->semStack[$stackPos-(9-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]));
            },
            482 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Closure(['static' => true, 'byRef' => $self->semStack[$stackPos-(10-4)], 'params' => $self->semStack[$stackPos-(10-6)], 'uses' => $self->semStack[$stackPos-(10-8)], 'returnType' => $self->semStack[$stackPos-(10-9)], 'stmts' => $self->semStack[$stackPos-(10-10)], 'attrGroups' => $self->semStack[$stackPos-(10-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(10-1)], $self->tokenEndStack[$stackPos]));
            },
            483 => static function ($self, $stackPos) {
                 $self->semValue = array(new Stmt\Class_(null, ['type' => $self->semStack[$stackPos-(8-2)], 'extends' => $self->semStack[$stackPos-(8-4)], 'implements' => $self->semStack[$stackPos-(8-5)], 'stmts' => $self->semStack[$stackPos-(8-7)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos])), $self->semStack[$stackPos-(8-3)]);
            $self->checkClass($self->semValue[0], -1);
            },
            484 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\New_($self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            485 => static function ($self, $stackPos) {
                 list($class, $ctorArgs) = $self->semStack[$stackPos-(2-2)]; $self->semValue = new Expr\New_($class, $ctorArgs, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            486 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            487 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(4-3)];
            },
            488 => null,
            489 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            490 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            491 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ClosureUse($self->semStack[$stackPos-(2-2)], $self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            492 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            493 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            494 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            495 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\FuncCall($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            496 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            497 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            498 => null,
            499 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            500 => static function ($self, $stackPos) {
                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            501 => static function ($self, $stackPos) {
                 $self->semValue = new Name\FullyQualified(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            502 => static function ($self, $stackPos) {
                 $self->semValue = new Name\Relative(substr($self->semStack[$stackPos-(1-1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            503 => null,
            504 => null,
            505 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            506 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            507 => null,
            508 => null,
            509 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            510 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            511 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            512 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]); foreach ($self->semValue as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); } };
            },
            513 => static function ($self, $stackPos) {
                 foreach ($self->semStack[$stackPos-(1-1)] as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '`', $self->phpVersion->supportsUnicodeEscapes()); } }; $self->semValue = $self->semStack[$stackPos-(1-1)];
            },
            514 => static function ($self, $stackPos) {
                 $self->semValue = array();
            },
            515 => null,
            516 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ConstFetch($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            517 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Line($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            518 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\File($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            519 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Dir($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            520 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Class_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            521 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Trait_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            522 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Method($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            523 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Function_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            524 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\MagicConst\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            525 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            526 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(5-1)], $self->semStack[$stackPos-(5-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));
            },
            527 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ClassConstFetch($self->semStack[$stackPos-(3-1)], new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)])), $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            528 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_SHORT;
            $self->semValue = new Expr\Array_($self->semStack[$stackPos-(3-2)], $attrs);
            },
            529 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\Array_::KIND_LONG;
            $self->semValue = new Expr\Array_($self->semStack[$stackPos-(4-3)], $attrs);
            $self->createdArrays->attach($self->semValue);
            },
            530 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->attach($self->semValue);
            },
            531 => static function ($self, $stackPos) {
                 $self->semValue = Scalar\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());
            },
            532 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Scalar\String_::KIND_DOUBLE_QUOTED;
            foreach ($self->semStack[$stackPos-(3-2)] as $s) { if ($s instanceof Node\InterpolatedStringPart) { $s->value = Node\Scalar\String_::parseEscapeSequences($s->value, '"', $self->phpVersion->supportsUnicodeEscapes()); } }; $self->semValue = new Scalar\InterpolatedString($self->semStack[$stackPos-(3-2)], $attrs);
            },
            533 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseLNumber($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals());
            },
            534 => static function ($self, $stackPos) {
                 $self->semValue = Scalar\Float_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            535 => null,
            536 => null,
            537 => null,
            538 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)]), true);
            },
            539 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(2-1)], '', $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(2-2)],  $self->tokenEndStack[$stackPos-(2-2)]), true);
            },
            540 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseDocString($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-2)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), $self->getAttributes($self->tokenStartStack[$stackPos-(3-3)],  $self->tokenEndStack[$stackPos-(3-3)]), true);
            },
            541 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            542 => null,
            543 => null,
            544 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            545 => null,
            546 => null,
            547 => null,
            548 => null,
            549 => null,
            550 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            551 => null,
            552 => null,
            553 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            554 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            555 => null,
            556 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\MethodCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            557 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafeMethodCall($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            558 => static function ($self, $stackPos) {
                 $self->semValue = null;
            },
            559 => null,
            560 => null,
            561 => null,
            562 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            563 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            564 => null,
            565 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            566 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            567 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable(new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos])), $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            568 => static function ($self, $stackPos) {
                 $var = $self->semStack[$stackPos-(1-1)]->name; $self->semValue = \is_string($var) ? new Node\VarLikeIdentifier($var, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])) : $var;
            },
            569 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            570 => null,
            571 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            572 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            573 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            574 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            575 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            576 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\StaticPropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            577 => null,
            578 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            579 => null,
            580 => null,
            581 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            582 => null,
            583 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;
            },
            584 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\List_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])); $self->semValue->setAttribute('kind', Expr\List_::KIND_LIST);
            $self->postprocessList($self->semValue);
            },
            585 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $end = count($self->semValue)-1; if ($self->semValue[$end]->value instanceof Expr\Error) array_pop($self->semValue);
            },
            586 => null,
            587 => static function ($self, $stackPos) {
                 /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */
            },
            588 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];
            },
            589 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            590 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            591 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(2-2)], null, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            592 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            593 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(3-3)], $self->semStack[$stackPos-(3-1)], false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            594 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(4-4)], $self->semStack[$stackPos-(4-1)], true, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            595 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(3-3)], $self->semStack[$stackPos-(3-1)], false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            596 => static function ($self, $stackPos) {
                 $self->semValue = new Node\ArrayItem($self->semStack[$stackPos-(2-2)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), true);
            },
            597 => static function ($self, $stackPos) {
                 /* Create an Error node now to remember the position. We'll later either report an error,
             or convert this into a null element, depending on whether this is a creation or destructuring context. */
          $attrs = $self->createEmptyElemAttributes($self->tokenPos);
          $self->semValue = new Node\ArrayItem(new Expr\Error($attrs), null, false, $attrs);
            },
            598 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            599 => static function ($self, $stackPos) {
                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];
            },
            600 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);
            },
            601 => static function ($self, $stackPos) {
                 $self->semValue = array($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)]);
            },
            602 => static function ($self, $stackPos) {
                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]); $attrs['rawValue'] = $self->semStack[$stackPos-(1-1)]; $self->semValue = new Node\InterpolatedStringPart($self->semStack[$stackPos-(1-1)], $attrs);
            },
            603 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            604 => null,
            605 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(4-1)], $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));
            },
            606 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\PropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            607 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\NullsafePropertyFetch($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            608 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            609 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));
            },
            610 => static function ($self, $stackPos) {
                 $self->semValue = new Expr\ArrayDimFetch($self->semStack[$stackPos-(6-2)], $self->semStack[$stackPos-(6-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(6-1)], $self->tokenEndStack[$stackPos]));
            },
            611 => static function ($self, $stackPos) {
                 $self->semValue = $self->semStack[$stackPos-(3-2)];
            },
            612 => static function ($self, $stackPos) {
                 $self->semValue = new Scalar\String_($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            613 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseNumString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));
            },
            614 => static function ($self, $stackPos) {
                 $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));
            },
            615 => null,
        ];
    }
}
Comment.php000064400000015255151520657540006701 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

class Comment implements \JsonSerializable {
    protected string $text;
    protected int $startLine;
    protected int $startFilePos;
    protected int $startTokenPos;
    protected int $endLine;
    protected int $endFilePos;
    protected int $endTokenPos;

    /**
     * Constructs a comment node.
     *
     * @param string $text Comment text (including comment delimiters like /*)
     * @param int $startLine Line number the comment started on
     * @param int $startFilePos File offset the comment started on
     * @param int $startTokenPos Token offset the comment started on
     */
    public function __construct(
        string $text,
        int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1,
        int $endLine = -1, int $endFilePos = -1, int $endTokenPos = -1
    ) {
        $this->text = $text;
        $this->startLine = $startLine;
        $this->startFilePos = $startFilePos;
        $this->startTokenPos = $startTokenPos;
        $this->endLine = $endLine;
        $this->endFilePos = $endFilePos;
        $this->endTokenPos = $endTokenPos;
    }

    /**
     * Gets the comment text.
     *
     * @return string The comment text (including comment delimiters like /*)
     */
    public function getText(): string {
        return $this->text;
    }

    /**
     * Gets the line number the comment started on.
     *
     * @return int Line number (or -1 if not available)
     */
    public function getStartLine(): int {
        return $this->startLine;
    }

    /**
     * Gets the file offset the comment started on.
     *
     * @return int File offset (or -1 if not available)
     */
    public function getStartFilePos(): int {
        return $this->startFilePos;
    }

    /**
     * Gets the token offset the comment started on.
     *
     * @return int Token offset (or -1 if not available)
     */
    public function getStartTokenPos(): int {
        return $this->startTokenPos;
    }

    /**
     * Gets the line number the comment ends on.
     *
     * @return int Line number (or -1 if not available)
     */
    public function getEndLine(): int {
        return $this->endLine;
    }

    /**
     * Gets the file offset the comment ends on.
     *
     * @return int File offset (or -1 if not available)
     */
    public function getEndFilePos(): int {
        return $this->endFilePos;
    }

    /**
     * Gets the token offset the comment ends on.
     *
     * @return int Token offset (or -1 if not available)
     */
    public function getEndTokenPos(): int {
        return $this->endTokenPos;
    }

    /**
     * Gets the comment text.
     *
     * @return string The comment text (including comment delimiters like /*)
     */
    public function __toString(): string {
        return $this->text;
    }

    /**
     * Gets the reformatted comment text.
     *
     * "Reformatted" here means that we try to clean up the whitespace at the
     * starts of the lines. This is necessary because we receive the comments
     * without leading whitespace on the first line, but with leading whitespace
     * on all subsequent lines.
     *
     * Additionally, this normalizes CRLF newlines to LF newlines.
     */
    public function getReformattedText(): string {
        $text = str_replace("\r\n", "\n", $this->text);
        $newlinePos = strpos($text, "\n");
        if (false === $newlinePos) {
            // Single line comments don't need further processing
            return $text;
        }
        if (preg_match('(^.*(?:\n\s+\*.*)+$)', $text)) {
            // Multi line comment of the type
            //
            //     /*
            //      * Some text.
            //      * Some more text.
            //      */
            //
            // is handled by replacing the whitespace sequences before the * by a single space
            return preg_replace('(^\s+\*)m', ' *', $text);
        }
        if (preg_match('(^/\*\*?\s*\n)', $text) && preg_match('(\n(\s*)\*/$)', $text, $matches)) {
            // Multi line comment of the type
            //
            //    /*
            //        Some text.
            //        Some more text.
            //    */
            //
            // is handled by removing the whitespace sequence on the line before the closing
            // */ on all lines. So if the last line is "    */", then "    " is removed at the
            // start of all lines.
            return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text);
        }
        if (preg_match('(^/\*\*?\s*(?!\s))', $text, $matches)) {
            // Multi line comment of the type
            //
            //     /* Some text.
            //        Some more text.
            //          Indented text.
            //        Even more text. */
            //
            // is handled by removing the difference between the shortest whitespace prefix on all
            // lines and the length of the "/* " opening sequence.
            $prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1));
            $removeLen = $prefixLen - strlen($matches[0]);
            return preg_replace('(^\s{' . $removeLen . '})m', '', $text);
        }

        // No idea how to format this comment, so simply return as is
        return $text;
    }

    /**
     * Get length of shortest whitespace prefix (at the start of a line).
     *
     * If there is a line with no prefix whitespace, 0 is a valid return value.
     *
     * @param string $str String to check
     * @return int Length in characters. Tabs count as single characters.
     */
    private function getShortestWhitespacePrefixLen(string $str): int {
        $lines = explode("\n", $str);
        $shortestPrefixLen = \PHP_INT_MAX;
        foreach ($lines as $line) {
            preg_match('(^\s*)', $line, $matches);
            $prefixLen = strlen($matches[0]);
            if ($prefixLen < $shortestPrefixLen) {
                $shortestPrefixLen = $prefixLen;
            }
        }
        return $shortestPrefixLen;
    }

    /**
     * @return array{nodeType:string, text:mixed, line:mixed, filePos:mixed}
     */
    public function jsonSerialize(): array {
        // Technically not a node, but we make it look like one anyway
        $type = $this instanceof Comment\Doc ? 'Comment_Doc' : 'Comment';
        return [
            'nodeType' => $type,
            'text' => $this->text,
            // TODO: Rename these to include "start".
            'line' => $this->startLine,
            'filePos' => $this->startFilePos,
            'tokenPos' => $this->startTokenPos,
            'endLine' => $this->endLine,
            'endFilePos' => $this->endFilePos,
            'endTokenPos' => $this->endTokenPos,
        ];
    }
}
NodeVisitor.php000064400000010123151520657540007531 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

interface NodeVisitor {
    /**
     * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes
     * of the current node will not be traversed for any visitors.
     *
     * For subsequent visitors enterNode() will still be called on the current
     * node and leaveNode() will also be invoked for the current node.
     */
    public const DONT_TRAVERSE_CHILDREN = 1;

    /**
     * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns
     * STOP_TRAVERSAL, traversal is aborted.
     *
     * The afterTraverse() method will still be invoked.
     */
    public const STOP_TRAVERSAL = 2;

    /**
     * If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs
     * in an array, it will be removed from the array.
     *
     * For subsequent visitors leaveNode() will still be invoked for the
     * removed node.
     */
    public const REMOVE_NODE = 3;

    /**
     * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes
     * of the current node will not be traversed for any visitors.
     *
     * For subsequent visitors enterNode() will not be called as well.
     * leaveNode() will be invoked for visitors that has enterNode() method invoked.
     */
    public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;

    /**
     * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns REPLACE_WITH_NULL,
     * the node will be replaced with null. This is not a legal return value if the node is part
     * of an array, rather than another node.
     */
    public const REPLACE_WITH_NULL = 5;

    /**
     * Called once before traversal.
     *
     * Return value semantics:
     *  * null:      $nodes stays as-is
     *  * otherwise: $nodes is set to the return value
     *
     * @param Node[] $nodes Array of nodes
     *
     * @return null|Node[] Array of nodes
     */
    public function beforeTraverse(array $nodes);

    /**
     * Called when entering a node.
     *
     * Return value semantics:
     *  * null
     *        => $node stays as-is
     *  * array (of Nodes)
     *        => The return value is merged into the parent array (at the position of the $node)
     *  * NodeVisitor::REMOVE_NODE
     *        => $node is removed from the parent array
     *  * NodeVisitor::REPLACE_WITH_NULL
     *        => $node is replaced with null
     *  * NodeVisitor::DONT_TRAVERSE_CHILDREN
     *        => Children of $node are not traversed. $node stays as-is
     *  * NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN
     *        => Further visitors for the current node are skipped, and its children are not
     *           traversed. $node stays as-is.
     *  * NodeVisitor::STOP_TRAVERSAL
     *        => Traversal is aborted. $node stays as-is
     *  * otherwise
     *        => $node is set to the return value
     *
     * @param Node $node Node
     *
     * @return null|int|Node|Node[] Replacement node (or special return value)
     */
    public function enterNode(Node $node);

    /**
     * Called when leaving a node.
     *
     * Return value semantics:
     *  * null
     *        => $node stays as-is
     *  * NodeVisitor::REMOVE_NODE
     *        => $node is removed from the parent array
     *  * NodeVisitor::REPLACE_WITH_NULL
     *        => $node is replaced with null
     *  * NodeVisitor::STOP_TRAVERSAL
     *        => Traversal is aborted. $node stays as-is
     *  * array (of Nodes)
     *        => The return value is merged into the parent array (at the position of the $node)
     *  * otherwise
     *        => $node is set to the return value
     *
     * @param Node $node Node
     *
     * @return null|int|Node|Node[] Replacement node (or special return value)
     */
    public function leaveNode(Node $node);

    /**
     * Called once after traversal.
     *
     * Return value semantics:
     *  * null:      $nodes stays as-is
     *  * otherwise: $nodes is set to the return value
     *
     * @param Node[] $nodes Array of nodes
     *
     * @return null|Node[] Array of nodes
     */
    public function afterTraverse(array $nodes);
}
BuilderHelpers.php000064400000023017151520657540010203 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\ComplexType;
use PhpParser\Node\Expr;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\NullableType;
use PhpParser\Node\Scalar;
use PhpParser\Node\Stmt;

/**
 * This class defines helpers used in the implementation of builders. Don't use it directly.
 *
 * @internal
 */
final class BuilderHelpers {
    /**
     * Normalizes a node: Converts builder objects to nodes.
     *
     * @param Node|Builder $node The node to normalize
     *
     * @return Node The normalized node
     */
    public static function normalizeNode($node): Node {
        if ($node instanceof Builder) {
            return $node->getNode();
        }

        if ($node instanceof Node) {
            return $node;
        }

        throw new \LogicException('Expected node or builder object');
    }

    /**
     * Normalizes a node to a statement.
     *
     * Expressions are wrapped in a Stmt\Expression node.
     *
     * @param Node|Builder $node The node to normalize
     *
     * @return Stmt The normalized statement node
     */
    public static function normalizeStmt($node): Stmt {
        $node = self::normalizeNode($node);
        if ($node instanceof Stmt) {
            return $node;
        }

        if ($node instanceof Expr) {
            return new Stmt\Expression($node);
        }

        throw new \LogicException('Expected statement or expression node');
    }

    /**
     * Normalizes strings to Identifier.
     *
     * @param string|Identifier $name The identifier to normalize
     *
     * @return Identifier The normalized identifier
     */
    public static function normalizeIdentifier($name): Identifier {
        if ($name instanceof Identifier) {
            return $name;
        }

        if (\is_string($name)) {
            return new Identifier($name);
        }

        throw new \LogicException('Expected string or instance of Node\Identifier');
    }

    /**
     * Normalizes strings to Identifier, also allowing expressions.
     *
     * @param string|Identifier|Expr $name The identifier to normalize
     *
     * @return Identifier|Expr The normalized identifier or expression
     */
    public static function normalizeIdentifierOrExpr($name) {
        if ($name instanceof Identifier || $name instanceof Expr) {
            return $name;
        }

        if (\is_string($name)) {
            return new Identifier($name);
        }

        throw new \LogicException('Expected string or instance of Node\Identifier or Node\Expr');
    }

    /**
     * Normalizes a name: Converts string names to Name nodes.
     *
     * @param Name|string $name The name to normalize
     *
     * @return Name The normalized name
     */
    public static function normalizeName($name): Name {
        if ($name instanceof Name) {
            return $name;
        }

        if (is_string($name)) {
            if (!$name) {
                throw new \LogicException('Name cannot be empty');
            }

            if ($name[0] === '\\') {
                return new Name\FullyQualified(substr($name, 1));
            }

            if (0 === strpos($name, 'namespace\\')) {
                return new Name\Relative(substr($name, strlen('namespace\\')));
            }

            return new Name($name);
        }

        throw new \LogicException('Name must be a string or an instance of Node\Name');
    }

    /**
     * Normalizes a name: Converts string names to Name nodes, while also allowing expressions.
     *
     * @param Expr|Name|string $name The name to normalize
     *
     * @return Name|Expr The normalized name or expression
     */
    public static function normalizeNameOrExpr($name) {
        if ($name instanceof Expr) {
            return $name;
        }

        if (!is_string($name) && !($name instanceof Name)) {
            throw new \LogicException(
                'Name must be a string or an instance of Node\Name or Node\Expr'
            );
        }

        return self::normalizeName($name);
    }

    /**
     * Normalizes a type: Converts plain-text type names into proper AST representation.
     *
     * In particular, builtin types become Identifiers, custom types become Names and nullables
     * are wrapped in NullableType nodes.
     *
     * @param string|Name|Identifier|ComplexType $type The type to normalize
     *
     * @return Name|Identifier|ComplexType The normalized type
     */
    public static function normalizeType($type) {
        if (!is_string($type)) {
            if (
                !$type instanceof Name && !$type instanceof Identifier &&
                !$type instanceof ComplexType
            ) {
                throw new \LogicException(
                    'Type must be a string, or an instance of Name, Identifier or ComplexType'
                );
            }
            return $type;
        }

        $nullable = false;
        if (strlen($type) > 0 && $type[0] === '?') {
            $nullable = true;
            $type = substr($type, 1);
        }

        $builtinTypes = [
            'array',
            'callable',
            'bool',
            'int',
            'float',
            'string',
            'iterable',
            'void',
            'object',
            'null',
            'false',
            'mixed',
            'never',
            'true',
        ];

        $lowerType = strtolower($type);
        if (in_array($lowerType, $builtinTypes)) {
            $type = new Identifier($lowerType);
        } else {
            $type = self::normalizeName($type);
        }

        $notNullableTypes = [
            'void', 'mixed', 'never',
        ];
        if ($nullable && in_array((string) $type, $notNullableTypes)) {
            throw new \LogicException(sprintf('%s type cannot be nullable', $type));
        }

        return $nullable ? new NullableType($type) : $type;
    }

    /**
     * Normalizes a value: Converts nulls, booleans, integers,
     * floats, strings and arrays into their respective nodes
     *
     * @param Node\Expr|bool|null|int|float|string|array $value The value to normalize
     *
     * @return Expr The normalized value
     */
    public static function normalizeValue($value): Expr {
        if ($value instanceof Node\Expr) {
            return $value;
        }

        if (is_null($value)) {
            return new Expr\ConstFetch(
                new Name('null')
            );
        }

        if (is_bool($value)) {
            return new Expr\ConstFetch(
                new Name($value ? 'true' : 'false')
            );
        }

        if (is_int($value)) {
            return new Scalar\Int_($value);
        }

        if (is_float($value)) {
            return new Scalar\Float_($value);
        }

        if (is_string($value)) {
            return new Scalar\String_($value);
        }

        if (is_array($value)) {
            $items = [];
            $lastKey = -1;
            foreach ($value as $itemKey => $itemValue) {
                // for consecutive, numeric keys don't generate keys
                if (null !== $lastKey && ++$lastKey === $itemKey) {
                    $items[] = new Node\ArrayItem(
                        self::normalizeValue($itemValue)
                    );
                } else {
                    $lastKey = null;
                    $items[] = new Node\ArrayItem(
                        self::normalizeValue($itemValue),
                        self::normalizeValue($itemKey)
                    );
                }
            }

            return new Expr\Array_($items);
        }

        throw new \LogicException('Invalid value');
    }

    /**
     * Normalizes a doc comment: Converts plain strings to PhpParser\Comment\Doc.
     *
     * @param Comment\Doc|string $docComment The doc comment to normalize
     *
     * @return Comment\Doc The normalized doc comment
     */
    public static function normalizeDocComment($docComment): Comment\Doc {
        if ($docComment instanceof Comment\Doc) {
            return $docComment;
        }

        if (is_string($docComment)) {
            return new Comment\Doc($docComment);
        }

        throw new \LogicException('Doc comment must be a string or an instance of PhpParser\Comment\Doc');
    }

    /**
     * Normalizes a attribute: Converts attribute to the Attribute Group if needed.
     *
     * @param Node\Attribute|Node\AttributeGroup $attribute
     *
     * @return Node\AttributeGroup The Attribute Group
     */
    public static function normalizeAttribute($attribute): Node\AttributeGroup {
        if ($attribute instanceof Node\AttributeGroup) {
            return $attribute;
        }

        if (!($attribute instanceof Node\Attribute)) {
            throw new \LogicException('Attribute must be an instance of PhpParser\Node\Attribute or PhpParser\Node\AttributeGroup');
        }

        return new Node\AttributeGroup([$attribute]);
    }

    /**
     * Adds a modifier and returns new modifier bitmask.
     *
     * @param int $modifiers Existing modifiers
     * @param int $modifier Modifier to set
     *
     * @return int New modifiers
     */
    public static function addModifier(int $modifiers, int $modifier): int {
        Modifiers::verifyModifier($modifiers, $modifier);
        return $modifiers | $modifier;
    }

    /**
     * Adds a modifier and returns new modifier bitmask.
     * @return int New modifiers
     */
    public static function addClassModifier(int $existingModifiers, int $modifierToSet): int {
        Modifiers::verifyClassModifier($existingModifiers, $modifierToSet);
        return $existingModifiers | $modifierToSet;
    }
}
NodeTraverser.php000064400000024715151520657540010063 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

class NodeTraverser implements NodeTraverserInterface {
    /**
     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CHILDREN instead.
     */
    public const DONT_TRAVERSE_CHILDREN = NodeVisitor::DONT_TRAVERSE_CHILDREN;

    /**
     * @deprecated Use NodeVisitor::STOP_TRAVERSAL instead.
     */
    public const STOP_TRAVERSAL = NodeVisitor::STOP_TRAVERSAL;

    /**
     * @deprecated Use NodeVisitor::REMOVE_NODE instead.
     */
    public const REMOVE_NODE = NodeVisitor::REMOVE_NODE;

    /**
     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN instead.
     */
    public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;

    /** @var list<NodeVisitor> Visitors */
    protected array $visitors = [];

    /** @var bool Whether traversal should be stopped */
    protected bool $stopTraversal;

    /**
     * Create a traverser with the given visitors.
     *
     * @param NodeVisitor ...$visitors Node visitors
     */
    public function __construct(NodeVisitor ...$visitors) {
        $this->visitors = $visitors;
    }

    /**
     * Adds a visitor.
     *
     * @param NodeVisitor $visitor Visitor to add
     */
    public function addVisitor(NodeVisitor $visitor): void {
        $this->visitors[] = $visitor;
    }

    /**
     * Removes an added visitor.
     */
    public function removeVisitor(NodeVisitor $visitor): void {
        $index = array_search($visitor, $this->visitors);
        if ($index !== false) {
            array_splice($this->visitors, $index, 1, []);
        }
    }

    /**
     * Traverses an array of nodes using the registered visitors.
     *
     * @param Node[] $nodes Array of nodes
     *
     * @return Node[] Traversed array of nodes
     */
    public function traverse(array $nodes): array {
        $this->stopTraversal = false;

        foreach ($this->visitors as $visitor) {
            if (null !== $return = $visitor->beforeTraverse($nodes)) {
                $nodes = $return;
            }
        }

        $nodes = $this->traverseArray($nodes);

        for ($i = \count($this->visitors) - 1; $i >= 0; --$i) {
            $visitor = $this->visitors[$i];
            if (null !== $return = $visitor->afterTraverse($nodes)) {
                $nodes = $return;
            }
        }

        return $nodes;
    }

    /**
     * Recursively traverse a node.
     *
     * @param Node $node Node to traverse.
     */
    protected function traverseNode(Node $node): void {
        foreach ($node->getSubNodeNames() as $name) {
            $subNode = $node->$name;

            if (\is_array($subNode)) {
                $node->$name = $this->traverseArray($subNode);
                if ($this->stopTraversal) {
                    break;
                }
            } elseif ($subNode instanceof Node) {
                $traverseChildren = true;
                $visitorIndex = -1;

                foreach ($this->visitors as $visitorIndex => $visitor) {
                    $return = $visitor->enterNode($subNode);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($subNode, $return);
                            $subNode = $node->$name = $return;
                        } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
                            $traverseChildren = false;
                        } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
                            $traverseChildren = false;
                            break;
                        } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            $node->$name = null;
                            continue 2;
                        } else {
                            throw new \LogicException(
                                'enterNode() returned invalid value of type ' . gettype($return)
                            );
                        }
                    }
                }

                if ($traverseChildren) {
                    $this->traverseNode($subNode);
                    if ($this->stopTraversal) {
                        break;
                    }
                }

                for (; $visitorIndex >= 0; --$visitorIndex) {
                    $visitor = $this->visitors[$visitorIndex];
                    $return = $visitor->leaveNode($subNode);

                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($subNode, $return);
                            $subNode = $node->$name = $return;
                        } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            $node->$name = null;
                            break;
                        } elseif (\is_array($return)) {
                            throw new \LogicException(
                                'leaveNode() may only return an array ' .
                                'if the parent structure is an array'
                            );
                        } else {
                            throw new \LogicException(
                                'leaveNode() returned invalid value of type ' . gettype($return)
                            );
                        }
                    }
                }
            }
        }
    }

    /**
     * Recursively traverse array (usually of nodes).
     *
     * @param array $nodes Array to traverse
     *
     * @return array Result of traversal (may be original array or changed one)
     */
    protected function traverseArray(array $nodes): array {
        $doNodes = [];

        foreach ($nodes as $i => $node) {
            if ($node instanceof Node) {
                $traverseChildren = true;
                $visitorIndex = -1;

                foreach ($this->visitors as $visitorIndex => $visitor) {
                    $return = $visitor->enterNode($node);
                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($node, $return);
                            $nodes[$i] = $node = $return;
                        } elseif (\is_array($return)) {
                            $doNodes[] = [$i, $return];
                            continue 2;
                        } elseif (NodeVisitor::REMOVE_NODE === $return) {
                            $doNodes[] = [$i, []];
                            continue 2;
                        } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {
                            $traverseChildren = false;
                        } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {
                            $traverseChildren = false;
                            break;
                        } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            throw new \LogicException(
                                'REPLACE_WITH_NULL can not be used if the parent structure is an array');
                        } else {
                            throw new \LogicException(
                                'enterNode() returned invalid value of type ' . gettype($return)
                            );
                        }
                    }
                }

                if ($traverseChildren) {
                    $this->traverseNode($node);
                    if ($this->stopTraversal) {
                        break;
                    }
                }

                for (; $visitorIndex >= 0; --$visitorIndex) {
                    $visitor = $this->visitors[$visitorIndex];
                    $return = $visitor->leaveNode($node);

                    if (null !== $return) {
                        if ($return instanceof Node) {
                            $this->ensureReplacementReasonable($node, $return);
                            $nodes[$i] = $node = $return;
                        } elseif (\is_array($return)) {
                            $doNodes[] = [$i, $return];
                            break;
                        } elseif (NodeVisitor::REMOVE_NODE === $return) {
                            $doNodes[] = [$i, []];
                            break;
                        } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {
                            $this->stopTraversal = true;
                            break 2;
                        } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {
                            throw new \LogicException(
                                'REPLACE_WITH_NULL can not be used if the parent structure is an array');
                        } else {
                            throw new \LogicException(
                                'leaveNode() returned invalid value of type ' . gettype($return)
                            );
                        }
                    }
                }
            } elseif (\is_array($node)) {
                throw new \LogicException('Invalid node structure: Contains nested arrays');
            }
        }

        if (!empty($doNodes)) {
            while (list($i, $replace) = array_pop($doNodes)) {
                array_splice($nodes, $i, 1, $replace);
            }
        }

        return $nodes;
    }

    private function ensureReplacementReasonable(Node $old, Node $new): void {
        if ($old instanceof Node\Stmt && $new instanceof Node\Expr) {
            throw new \LogicException(
                "Trying to replace statement ({$old->getType()}) " .
                "with expression ({$new->getType()}). Are you missing a " .
                "Stmt_Expression wrapper?"
            );
        }

        if ($old instanceof Node\Expr && $new instanceof Node\Stmt) {
            throw new \LogicException(
                "Trying to replace expression ({$old->getType()}) " .
                "with statement ({$new->getType()})"
            );
        }
    }
}
BuilderFactory.php000064400000024453151520657540010215 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\BinaryOp\Concat;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Use_;

class BuilderFactory {
    /**
     * Creates an attribute node.
     *
     * @param string|Name $name Name of the attribute
     * @param array $args Attribute named arguments
     */
    public function attribute($name, array $args = []): Node\Attribute {
        return new Node\Attribute(
            BuilderHelpers::normalizeName($name),
            $this->args($args)
        );
    }

    /**
     * Creates a namespace builder.
     *
     * @param null|string|Node\Name $name Name of the namespace
     *
     * @return Builder\Namespace_ The created namespace builder
     */
    public function namespace($name): Builder\Namespace_ {
        return new Builder\Namespace_($name);
    }

    /**
     * Creates a class builder.
     *
     * @param string $name Name of the class
     *
     * @return Builder\Class_ The created class builder
     */
    public function class(string $name): Builder\Class_ {
        return new Builder\Class_($name);
    }

    /**
     * Creates an interface builder.
     *
     * @param string $name Name of the interface
     *
     * @return Builder\Interface_ The created interface builder
     */
    public function interface(string $name): Builder\Interface_ {
        return new Builder\Interface_($name);
    }

    /**
     * Creates a trait builder.
     *
     * @param string $name Name of the trait
     *
     * @return Builder\Trait_ The created trait builder
     */
    public function trait(string $name): Builder\Trait_ {
        return new Builder\Trait_($name);
    }

    /**
     * Creates an enum builder.
     *
     * @param string $name Name of the enum
     *
     * @return Builder\Enum_ The created enum builder
     */
    public function enum(string $name): Builder\Enum_ {
        return new Builder\Enum_($name);
    }

    /**
     * Creates a trait use builder.
     *
     * @param Node\Name|string ...$traits Trait names
     *
     * @return Builder\TraitUse The created trait use builder
     */
    public function useTrait(...$traits): Builder\TraitUse {
        return new Builder\TraitUse(...$traits);
    }

    /**
     * Creates a trait use adaptation builder.
     *
     * @param Node\Name|string|null $trait Trait name
     * @param Node\Identifier|string $method Method name
     *
     * @return Builder\TraitUseAdaptation The created trait use adaptation builder
     */
    public function traitUseAdaptation($trait, $method = null): Builder\TraitUseAdaptation {
        if ($method === null) {
            $method = $trait;
            $trait = null;
        }

        return new Builder\TraitUseAdaptation($trait, $method);
    }

    /**
     * Creates a method builder.
     *
     * @param string $name Name of the method
     *
     * @return Builder\Method The created method builder
     */
    public function method(string $name): Builder\Method {
        return new Builder\Method($name);
    }

    /**
     * Creates a parameter builder.
     *
     * @param string $name Name of the parameter
     *
     * @return Builder\Param The created parameter builder
     */
    public function param(string $name): Builder\Param {
        return new Builder\Param($name);
    }

    /**
     * Creates a property builder.
     *
     * @param string $name Name of the property
     *
     * @return Builder\Property The created property builder
     */
    public function property(string $name): Builder\Property {
        return new Builder\Property($name);
    }

    /**
     * Creates a function builder.
     *
     * @param string $name Name of the function
     *
     * @return Builder\Function_ The created function builder
     */
    public function function(string $name): Builder\Function_ {
        return new Builder\Function_($name);
    }

    /**
     * Creates a namespace/class use builder.
     *
     * @param Node\Name|string $name Name of the entity (namespace or class) to alias
     *
     * @return Builder\Use_ The created use builder
     */
    public function use($name): Builder\Use_ {
        return new Builder\Use_($name, Use_::TYPE_NORMAL);
    }

    /**
     * Creates a function use builder.
     *
     * @param Node\Name|string $name Name of the function to alias
     *
     * @return Builder\Use_ The created use function builder
     */
    public function useFunction($name): Builder\Use_ {
        return new Builder\Use_($name, Use_::TYPE_FUNCTION);
    }

    /**
     * Creates a constant use builder.
     *
     * @param Node\Name|string $name Name of the const to alias
     *
     * @return Builder\Use_ The created use const builder
     */
    public function useConst($name): Builder\Use_ {
        return new Builder\Use_($name, Use_::TYPE_CONSTANT);
    }

    /**
     * Creates a class constant builder.
     *
     * @param string|Identifier $name Name
     * @param Node\Expr|bool|null|int|float|string|array $value Value
     *
     * @return Builder\ClassConst The created use const builder
     */
    public function classConst($name, $value): Builder\ClassConst {
        return new Builder\ClassConst($name, $value);
    }

    /**
     * Creates an enum case builder.
     *
     * @param string|Identifier $name Name
     *
     * @return Builder\EnumCase The created use const builder
     */
    public function enumCase($name): Builder\EnumCase {
        return new Builder\EnumCase($name);
    }

    /**
     * Creates node a for a literal value.
     *
     * @param Expr|bool|null|int|float|string|array $value $value
     */
    public function val($value): Expr {
        return BuilderHelpers::normalizeValue($value);
    }

    /**
     * Creates variable node.
     *
     * @param string|Expr $name Name
     */
    public function var($name): Expr\Variable {
        if (!\is_string($name) && !$name instanceof Expr) {
            throw new \LogicException('Variable name must be string or Expr');
        }

        return new Expr\Variable($name);
    }

    /**
     * Normalizes an argument list.
     *
     * Creates Arg nodes for all arguments and converts literal values to expressions.
     *
     * @param array $args List of arguments to normalize
     *
     * @return list<Arg>
     */
    public function args(array $args): array {
        $normalizedArgs = [];
        foreach ($args as $key => $arg) {
            if (!($arg instanceof Arg)) {
                $arg = new Arg(BuilderHelpers::normalizeValue($arg));
            }
            if (\is_string($key)) {
                $arg->name = BuilderHelpers::normalizeIdentifier($key);
            }
            $normalizedArgs[] = $arg;
        }
        return $normalizedArgs;
    }

    /**
     * Creates a function call node.
     *
     * @param string|Name|Expr $name Function name
     * @param array $args Function arguments
     */
    public function funcCall($name, array $args = []): Expr\FuncCall {
        return new Expr\FuncCall(
            BuilderHelpers::normalizeNameOrExpr($name),
            $this->args($args)
        );
    }

    /**
     * Creates a method call node.
     *
     * @param Expr $var Variable the method is called on
     * @param string|Identifier|Expr $name Method name
     * @param array $args Method arguments
     */
    public function methodCall(Expr $var, $name, array $args = []): Expr\MethodCall {
        return new Expr\MethodCall(
            $var,
            BuilderHelpers::normalizeIdentifierOrExpr($name),
            $this->args($args)
        );
    }

    /**
     * Creates a static method call node.
     *
     * @param string|Name|Expr $class Class name
     * @param string|Identifier|Expr $name Method name
     * @param array $args Method arguments
     */
    public function staticCall($class, $name, array $args = []): Expr\StaticCall {
        return new Expr\StaticCall(
            BuilderHelpers::normalizeNameOrExpr($class),
            BuilderHelpers::normalizeIdentifierOrExpr($name),
            $this->args($args)
        );
    }

    /**
     * Creates an object creation node.
     *
     * @param string|Name|Expr $class Class name
     * @param array $args Constructor arguments
     */
    public function new($class, array $args = []): Expr\New_ {
        return new Expr\New_(
            BuilderHelpers::normalizeNameOrExpr($class),
            $this->args($args)
        );
    }

    /**
     * Creates a constant fetch node.
     *
     * @param string|Name $name Constant name
     */
    public function constFetch($name): Expr\ConstFetch {
        return new Expr\ConstFetch(BuilderHelpers::normalizeName($name));
    }

    /**
     * Creates a property fetch node.
     *
     * @param Expr $var Variable holding object
     * @param string|Identifier|Expr $name Property name
     */
    public function propertyFetch(Expr $var, $name): Expr\PropertyFetch {
        return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name));
    }

    /**
     * Creates a class constant fetch node.
     *
     * @param string|Name|Expr $class Class name
     * @param string|Identifier|Expr $name Constant name
     */
    public function classConstFetch($class, $name): Expr\ClassConstFetch {
        return new Expr\ClassConstFetch(
            BuilderHelpers::normalizeNameOrExpr($class),
            BuilderHelpers::normalizeIdentifierOrExpr($name)
        );
    }

    /**
     * Creates nested Concat nodes from a list of expressions.
     *
     * @param Expr|string ...$exprs Expressions or literal strings
     */
    public function concat(...$exprs): Concat {
        $numExprs = count($exprs);
        if ($numExprs < 2) {
            throw new \LogicException('Expected at least two expressions');
        }

        $lastConcat = $this->normalizeStringExpr($exprs[0]);
        for ($i = 1; $i < $numExprs; $i++) {
            $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i]));
        }
        return $lastConcat;
    }

    /**
     * @param string|Expr $expr
     */
    private function normalizeStringExpr($expr): Expr {
        if ($expr instanceof Expr) {
            return $expr;
        }

        if (\is_string($expr)) {
            return new String_($expr);
        }

        throw new \LogicException('Expected string or Expr');
    }
}
PrettyPrinter.php000064400000003243151520657540010124 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\Node\Expr;

interface PrettyPrinter {
    /**
     * Pretty prints an array of statements.
     *
     * @param Node[] $stmts Array of statements
     *
     * @return string Pretty printed statements
     */
    public function prettyPrint(array $stmts): string;

    /**
     * Pretty prints an expression.
     *
     * @param Expr $node Expression node
     *
     * @return string Pretty printed node
     */
    public function prettyPrintExpr(Expr $node): string;

    /**
     * Pretty prints a file of statements (includes the opening <?php tag if it is required).
     *
     * @param Node[] $stmts Array of statements
     *
     * @return string Pretty printed statements
     */
    public function prettyPrintFile(array $stmts): string;

    /**
     * Perform a format-preserving pretty print of an AST.
     *
     * The format preservation is best effort. For some changes to the AST the formatting will not
     * be preserved (at least not locally).
     *
     * In order to use this method a number of prerequisites must be satisfied:
     *  * The startTokenPos and endTokenPos attributes in the lexer must be enabled.
     *  * The CloningVisitor must be run on the AST prior to modification.
     *  * The original tokens must be provided, using the getTokens() method on the lexer.
     *
     * @param Node[] $stmts Modified AST with links to original AST
     * @param Node[] $origStmts Original AST with token offset information
     * @param Token[] $origTokens Tokens of the original code
     */
    public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string;
}
NodeVisitorAbstract.php000064400000000677151520657540011232 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

/**
 * @codeCoverageIgnore
 */
abstract class NodeVisitorAbstract implements NodeVisitor {
    public function beforeTraverse(array $nodes) {
        return null;
    }

    public function enterNode(Node $node) {
        return null;
    }

    public function leaveNode(Node $node) {
        return null;
    }

    public function afterTraverse(array $nodes) {
        return null;
    }
}
ConstExprEvaluationException.php000064400000000160151520657540013120 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

class ConstExprEvaluationException extends \Exception {
}
NodeFinder.php000064400000005057151520657540007313 0ustar00<?php declare(strict_types=1);

namespace PhpParser;

use PhpParser\NodeVisitor\FindingVisitor;
use PhpParser\NodeVisitor\FirstFindingVisitor;

class NodeFinder {
    /**
     * Find all nodes satisfying a filter callback.
     *
     * @param Node|Node[] $nodes Single node or array of nodes to search in
     * @param callable $filter Filter callback: function(Node $node) : bool
     *
     * @return Node[] Found nodes satisfying the filter callback
     */
    public function find($nodes, callable $filter): array {
        if ($nodes === []) {
            return [];
        }

        if (!is_array($nodes)) {
            $nodes = [$nodes];
        }

        $visitor = new FindingVisitor($filter);

        $traverser = new NodeTraverser($visitor);
        $traverser->traverse($nodes);

        return $visitor->getFoundNodes();
    }

    /**
     * Find all nodes that are instances of a certain class.

     * @template TNode as Node
     *
     * @param Node|Node[] $nodes Single node or array of nodes to search in
     * @param class-string<TNode> $class Class name
     *
     * @return TNode[] Found nodes (all instances of $class)
     */
    public function findInstanceOf($nodes, string $class): array {
        return $this->find($nodes, function ($node) use ($class) {
            return $node instanceof $class;
        });
    }

    /**
     * Find first node satisfying a filter callback.
     *
     * @param Node|Node[] $nodes Single node or array of nodes to search in
     * @param callable $filter Filter callback: function(Node $node) : bool
     *
     * @return null|Node Found node (or null if none found)
     */
    public function findFirst($nodes, callable $filter): ?Node {
        if ($nodes === []) {
            return null;
        }

        if (!is_array($nodes)) {
            $nodes = [$nodes];
        }

        $visitor = new FirstFindingVisitor($filter);

        $traverser = new NodeTraverser($visitor);
        $traverser->traverse($nodes);

        return $visitor->getFoundNode();
    }

    /**
     * Find first node that is an instance of a certain class.
     *
     * @template TNode as Node
     *
     * @param Node|Node[] $nodes Single node or array of nodes to search in
     * @param class-string<TNode> $class Class name
     *
     * @return null|TNode Found node, which is an instance of $class (or null if none found)
     */
    public function findFirstInstanceOf($nodes, string $class): ?Node {
        return $this->findFirst($nodes, function ($node) use ($class) {
            return $node instanceof $class;
        });
    }
}