{"dirs":["/typephp","/typephp/src","/typephp/vendor","/typephp/src/Exception","/typephp/src/Extension","/typephp/src/Internal","/typephp/vendor/nikic","/typephp/vendor/phpstan","/typephp/src/Internal/Ast","/typephp/src/Internal/Checker","/typephp/src/Internal/Cli","/typephp/src/Internal/Diagnostic","/typephp/src/Internal/Docblock","/typephp/src/Internal/Generics","/typephp/src/Internal/Io","/typephp/src/Internal/Resolver","/typephp/src/Internal/Util","/typephp/src/Internal/Validator","/typephp/src/Internal/Wrapper","/typephp/vendor/nikic/php-parser","/typephp/vendor/phpstan/phpdoc-parser","/typephp/vendor/nikic/php-parser/lib","/typephp/vendor/phpstan/phpdoc-parser/src","/typephp/vendor/nikic/php-parser/lib/PhpParser","/typephp/vendor/phpstan/phpdoc-parser/src/Ast","/typephp/vendor/phpstan/phpdoc-parser/src/Lexer","/typephp/vendor/phpstan/phpdoc-parser/src/Parser","/typephp/vendor/phpstan/phpdoc-parser/src/Printer","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder","/typephp/vendor/nikic/php-parser/lib/PhpParser/Comment","/typephp/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor","/typephp/vendor/nikic/php-parser/lib/PhpParser/Parser","/typephp/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Name","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation"],"files":{"/typephp/src/Exception/TypeError.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Exception;\n\n/**\n * Custom TypeError thrown when a PHPDoc type contract (parameter, return, or variable) is violated.\n * Extends PHP's native \\TypeError for full polymorphic compatibility.\n */\nclass TypeError extends \\TypeError\n{\n}\n","/typephp/src/Extension/ExtensionInterface.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Extension;\n\n/**\n * Interface for third-party extensions providing automatic configuration overrides (include paths and stub files).\n */\ninterface ExtensionInterface\n{\n    /**\n     * Returns configuration array (include and stubs) to merge into TypePHP.\n     *\n     * @return array<string, mixed>\n     */\n    public function getConfig(): array;\n}\n","/typephp/src/Internal/Ast/ContractVisitor.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\nuse TypePHP\\Internal\\Docblock\\DocblockExtractor;\nuse TypePHP\\Internal\\Util\\Config;\n\n/**\n * @internal AST Node Visitor that injects contract checks, scope tracking, property hook validation, and parameter/return wrappers into functions and methods.\n */\nfinal class ContractVisitor extends NodeVisitorAbstract\n{\n    private const ASSIGN_OP_MAP = [\n        Node\\Expr\\AssignOp\\Plus::class => Node\\Expr\\BinaryOp\\Plus::class,\n        Node\\Expr\\AssignOp\\Minus::class => Node\\Expr\\BinaryOp\\Minus::class,\n        Node\\Expr\\AssignOp\\Mul::class => Node\\Expr\\BinaryOp\\Mul::class,\n        Node\\Expr\\AssignOp\\Div::class => Node\\Expr\\BinaryOp\\Div::class,\n        Node\\Expr\\AssignOp\\Mod::class => Node\\Expr\\BinaryOp\\Mod::class,\n        Node\\Expr\\AssignOp\\Concat::class => Node\\Expr\\BinaryOp\\Concat::class,\n        Node\\Expr\\AssignOp\\Pow::class => Node\\Expr\\BinaryOp\\Pow::class,\n        Node\\Expr\\AssignOp\\BitwiseAnd::class => Node\\Expr\\BinaryOp\\BitwiseAnd::class,\n        Node\\Expr\\AssignOp\\BitwiseOr::class => Node\\Expr\\BinaryOp\\BitwiseOr::class,\n        Node\\Expr\\AssignOp\\BitwiseXor::class => Node\\Expr\\BinaryOp\\BitwiseXor::class,\n        Node\\Expr\\AssignOp\\ShiftLeft::class => Node\\Expr\\BinaryOp\\ShiftLeft::class,\n        Node\\Expr\\AssignOp\\ShiftRight::class => Node\\Expr\\BinaryOp\\ShiftRight::class,\n        Node\\Expr\\AssignOp\\Coalesce::class => Node\\Expr\\BinaryOp\\Coalesce::class,\n    ];\n\n    private ScopeManager $scopeManager;\n\n    private string $currentNamespace = '';\n\n    /**\n     * @var list<array{name: ?string, isAnonymous: bool, hasInheritance: bool, hasPropertyWithDoc: bool, isReadonly: bool, hasTemplates: bool}>\n     */\n    private array $classStack = [];\n\n    /**\n     * @var list<array{name: string, isStatic: bool}>\n     */\n    private array $methodStack = [];\n\n    /**\n     * @var list<string>\n     */\n    private array $functionStack = [];\n\n    /**\n     * @var list<bool>\n     */\n    private array $thisAvailableStack = [];\n\n    public function __construct()\n    {\n        $this->scopeManager = new ScopeManager();\n    }\n\n    /**\n     * Traverses and transforms AST nodes during entry.\n     *\n     * @return array<Node>|null\n     */\n    public function enterNode(Node $node): ?array\n    {\n        $this->trackDeclarationEntry($node);\n\n        if ($this->isScopeBoundary($node)) {\n            $this->scopeManager->pushScope();\n        }\n\n        if ($node instanceof Node\\Expr\\Assign || $node instanceof Node\\Expr\\AssignOp) {\n            $this->markWriteContext($node->var);\n        } elseif ($node instanceof Node\\Expr\\PreInc || $node instanceof Node\\Expr\\PostInc || $node instanceof Node\\Expr\\PreDec || $node instanceof Node\\Expr\\PostDec) {\n            $this->markWriteContext($node->var);\n        } elseif ($node instanceof Node\\Stmt\\Unset_) {\n            foreach ($node->vars as $v) {\n                $this->markWriteContext($v);\n            }\n        }\n\n        if ($node instanceof Node\\Stmt\\Class_) {\n            $this->processClassPropertyDefaults($node);\n        }\n\n        if ($node instanceof Node\\Stmt\\Function_ || $node instanceof Node\\Stmt\\ClassMethod) {\n            $classContext = $this->classStack !== [] ? end($this->classStack) : null;\n            FunctionContractInjector::inject($node, $classContext);\n\n            return null;\n        }\n\n        if ($node instanceof Node\\Stmt\\Property) {\n            PropertyHookInjector::process($node);\n\n            return null;\n        }\n\n        if ($node instanceof Node\\Stmt\\Return_) {\n            $this->handleReturn($node);\n\n            return null;\n        }\n\n        if ($node instanceof Node\\Stmt\\Expression) {\n            return $this->handleExpression($node);\n        }\n\n        if ($node instanceof Node\\Stmt\\Foreach_) {\n            $doc = $node->getDocComment();\n            if ($doc !== null && str_contains($doc->getText(), '@var')) {\n                $this->scopeManager->extractVarDocblock($doc->getText(), $node->valueVar);\n            }\n\n            return null;\n        }\n\n        if ($node instanceof Node\\Expr\\Assign) {\n            $this->handleAssign($node);\n        }\n\n        return null;\n    }\n\n    /**\n     * Pops the current lexical scope stack frame or replaces transformed expressions upon leaving a node.\n     */\n    public function leaveNode(Node $node): ?Node\n    {\n        $this->trackDeclarationExit($node);\n\n        if ($node instanceof Node\\Expr\\Clone_) {\n            return $this->wrapClone($node);\n        }\n\n        if ($node instanceof Node\\Expr\\AssignOp) {\n            $replacement = $this->handleAssignOp($node);\n            if ($replacement !== null) {\n                return $replacement;\n            }\n        }\n\n        if ($node instanceof Node\\Expr\\PreInc || $node instanceof Node\\Expr\\PostInc || $node instanceof Node\\Expr\\PreDec || $node instanceof Node\\Expr\\PostDec) {\n            $replacement = $this->handleIncDec($node);\n            if ($replacement !== null) {\n                return $replacement;\n            }\n        }\n\n        if ($node instanceof Node\\Expr\\StaticPropertyFetch && $node->name instanceof Node\\VarLikeIdentifier) {\n            $propName = $node->name->toString();\n\n            if ($node->getAttribute('typephp_checked') !== true && $node->getAttribute('typephp_write_context') !== true) {\n                $node->setAttribute('typephp_checked', true);\n                $classArg = $node->class instanceof Node\\Name\n                    ? new Node\\Expr\\ClassConstFetch($node->class, 'class')\n                    : $node->class;\n\n                return new Node\\Expr\\StaticCall(\n                    new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker'),\n                    'checkStaticProperty',\n                    [\n                        new Node\\Arg($classArg),\n                        new Node\\Arg(new Node\\Scalar\\String_($propName)),\n                        new Node\\Arg($node),\n                        new Node\\Arg(new Node\\Scalar\\MagicConst\\File()),\n                        new Node\\Arg(new Node\\Scalar\\LNumber($node->getStartLine())),\n                    ]\n                );\n            }\n        }\n\n        if ($this->isScopeBoundary($node)) {\n            $this->scopeManager->popScope();\n        }\n\n        return null;\n    }\n\n    private function markWriteContext(Node $node): void\n    {\n        $node->setAttribute('typephp_write_context', true);\n        if ($node instanceof Node\\Expr\\ArrayDimFetch || $node instanceof Node\\Expr\\PropertyFetch) {\n            $this->markWriteContext($node->var);\n        }\n    }\n\n    private function processClassPropertyDefaults(Node\\Stmt\\Class_ $node): void\n    {\n        if (! Config::isInlinePropertiesEnabled()) {\n            return;\n        }\n\n        $defaultProps = [];\n        $hasConstructor = false;\n\n        foreach ($node->stmts as $stmt) {\n            if ($stmt instanceof Node\\Stmt\\ClassMethod && strtolower($stmt->name->toString()) === '__construct') {\n                $hasConstructor = true;\n            } elseif ($stmt instanceof Node\\Stmt\\Property && ! $stmt->isStatic()) {\n                $doc = $stmt->getDocComment();\n                if ($doc !== null && str_contains($doc->getText(), '@var') && ! str_contains($doc->getText(), '@typephp-ignore')) {\n                    foreach ($stmt->props as $p) {\n                        $isExplicitNull = $p->default instanceof Node\\Expr\\ConstFetch && strtolower($p->default->name->toString()) === 'null';\n                        if ($p->default !== null && ! $isExplicitNull) {\n                            $defaultProps[] = [\n                                'name' => $p->name->toString(),\n                                'line' => $p->getStartLine(),\n                            ];\n                        }\n                    }\n                }\n            }\n        }\n\n        if ($defaultProps === []) {\n            return;\n        }\n\n        if (! $hasConstructor) {\n            $ctorStmts = [];\n            if ($node->extends !== null) {\n                $ctorStmts[] = new Node\\Stmt\\If_(\n                    new Node\\Expr\\FuncCall(new Node\\Name('method_exists'), [\n                        new Node\\Arg(new Node\\Expr\\ClassConstFetch(new Node\\Name('parent'), 'class')),\n                        new Node\\Arg(new Node\\Scalar\\String_('__construct')),\n                    ]),\n                    ['stmts' => [\n                        new Node\\Stmt\\Expression(new Node\\Expr\\StaticCall(new Node\\Name('parent'), '__construct', [new Node\\Arg(new Node\\Expr\\Variable('_typephp_ctor_args'), false, true)])),\n                    ]]\n                );\n            }\n\n            foreach ($defaultProps as $dp) {\n                $checkCall = NodeBuilder::createPropertyCheckCall(\n                    new Node\\Expr\\PropertyFetch(new Node\\Expr\\Variable('this'), $dp['name']),\n                    new Node\\Expr\\Variable('this'),\n                    $dp['name']\n                );\n                $stmt = new Node\\Stmt\\Expression(NodeBuilder::createTernaryThrowExpr($checkCall, $dp['line']));\n                $stmt->setAttribute('typephp_injected', true);\n                $ctorStmts[] = $stmt;\n            }\n\n            $ctor = new Node\\Stmt\\ClassMethod('__construct', [\n                'flags' => Node\\Stmt\\Class_::MODIFIER_PUBLIC,\n                'params' => [new Node\\Param(new Node\\Expr\\Variable('_typephp_ctor_args'), null, null, false, true)],\n                'stmts' => $ctorStmts,\n            ]);\n            $ctor->setAttribute('typephp_injected', true);\n            $node->stmts[] = $ctor;\n        } else {\n            foreach ($node->stmts as $stmt) {\n                if ($stmt instanceof Node\\Stmt\\ClassMethod && strtolower($stmt->name->toString()) === '__construct') {\n                    $injected = [];\n                    foreach ($defaultProps as $dp) {\n                        $checkCall = NodeBuilder::createPropertyCheckCall(\n                            new Node\\Expr\\PropertyFetch(new Node\\Expr\\Variable('this'), $dp['name']),\n                            new Node\\Expr\\Variable('this'),\n                            $dp['name']\n                        );\n                        $checkStmt = new Node\\Stmt\\Expression(NodeBuilder::createTernaryThrowExpr($checkCall, $dp['line']));\n                        $checkStmt->setAttribute('typephp_injected', true);\n                        $injected[] = $checkStmt;\n                    }\n                    $stmt->stmts = [...$injected, ...($stmt->stmts ?? [])];\n\n                    break;\n                }\n            }\n        }\n    }\n\n    private function trackDeclarationEntry(Node $node): void\n    {\n        if ($node instanceof Node\\Stmt\\Namespace_) {\n            $this->currentNamespace = $node->name !== null ? $node->name->toString() : '';\n        } elseif (\n            $node instanceof Node\\Stmt\\Class_\n            || $node instanceof Node\\Stmt\\Interface_\n            || $node instanceof Node\\Stmt\\Trait_\n            || $node instanceof Node\\Stmt\\Enum_\n        ) {\n            $this->enterClassLike($node);\n        } elseif ($node instanceof Node\\Stmt\\ClassMethod) {\n            $this->methodStack[] = ['name' => $node->name->toString(), 'isStatic' => $node->isStatic()];\n            $this->thisAvailableStack[] = ! $node->isStatic();\n        } elseif ($node instanceof Node\\Stmt\\Function_) {\n            $this->functionStack[] = $this->resolveQualifiedName($node->name) ?? '';\n            $this->thisAvailableStack[] = false;\n        } elseif ($node instanceof Node\\Expr\\Closure || $node instanceof Node\\Expr\\ArrowFunction) {\n            $this->thisAvailableStack[] = ! $node->static;\n        }\n    }\n\n    private function trackDeclarationExit(Node $node): void\n    {\n        if ($node instanceof Node\\Stmt\\Namespace_) {\n            $this->currentNamespace = '';\n        } elseif (\n            $node instanceof Node\\Stmt\\Class_\n            || $node instanceof Node\\Stmt\\Interface_\n            || $node instanceof Node\\Stmt\\Trait_\n            || $node instanceof Node\\Stmt\\Enum_\n        ) {\n            array_pop($this->classStack);\n        } elseif ($node instanceof Node\\Stmt\\ClassMethod) {\n            array_pop($this->methodStack);\n            array_pop($this->thisAvailableStack);\n        } elseif ($node instanceof Node\\Stmt\\Function_) {\n            array_pop($this->functionStack);\n            array_pop($this->thisAvailableStack);\n        } elseif ($node instanceof Node\\Expr\\Closure || $node instanceof Node\\Expr\\ArrowFunction) {\n            array_pop($this->thisAvailableStack);\n        }\n    }\n\n    private function enterClassLike(Node\\Stmt\\Class_|Node\\Stmt\\Interface_|Node\\Stmt\\Trait_|Node\\Stmt\\Enum_ $node): void\n    {\n        $typeName = $this->resolveQualifiedName($node->name);\n        $hasInheritance = true;\n        $hasRealInheritance = false;\n        $hasPropertyWithDoc = false;\n        $isReadonly = false;\n        $hasTemplates = false;\n\n        if ($node instanceof Node\\Stmt\\Class_) {\n            $hasExtends = $node->extends !== null;\n            $hasImplements = $node->implements !== [];\n            $hasTraits = false;\n            $isReadonly = ($node->flags & Node\\Stmt\\Class_::MODIFIER_READONLY) !== 0;\n\n            foreach ($node->stmts as $stmt) {\n                if ($stmt instanceof Node\\Stmt\\TraitUse) {\n                    $hasTraits = true;\n                } elseif ($stmt instanceof Node\\Stmt\\Property && $stmt->getDocComment() !== null) {\n                    $hasPropertyWithDoc = true;\n                }\n            }\n\n            $doc = $node->getDocComment();\n            $hasTemplates = $doc !== null && (\n                str_contains($doc->getText(), '@template')\n                || str_contains($doc->getText(), '@phpstan-template')\n                || str_contains($doc->getText(), '@psalm-template')\n            );\n            $hasClassDoc = $doc !== null && (\n                $hasTemplates\n                || str_contains($doc->getText(), '@phpstan-')\n                || str_contains($doc->getText(), '@psalm-')\n                || str_contains($doc->getText(), '@method')\n                || str_contains($doc->getText(), '@property')\n            );\n\n            $hasRealInheritance = $hasExtends || $hasImplements || $hasTraits;\n            $hasInheritance = $hasRealInheritance || $hasClassDoc;\n        } elseif ($node instanceof Node\\Stmt\\Enum_) {\n            $hasRealInheritance = $node->implements !== [];\n            $hasInheritance = $hasRealInheritance;\n        } else {\n            $doc = $node->getDocComment();\n            $hasTemplates = $doc !== null && (\n                str_contains($doc->getText(), '@template')\n                || str_contains($doc->getText(), '@phpstan-template')\n                || str_contains($doc->getText(), '@psalm-template')\n            );\n        }\n\n        $this->classStack[] = [\n            'name' => $typeName,\n            'isAnonymous' => ($node instanceof Node\\Stmt\\Class_ && $node->name === null),\n            'hasInheritance' => $hasInheritance,\n            'hasRealInheritance' => $hasRealInheritance,\n            'hasPropertyWithDoc' => $hasPropertyWithDoc,\n            'isReadonly' => $isReadonly,\n            'hasTemplates' => $hasTemplates,\n        ];\n    }\n\n    private function handleReturn(Node\\Stmt\\Return_ $node): void\n    {\n        if ($node->expr === null) {\n            return;\n        }\n\n        $doc = $node->getDocComment();\n        if ($doc === null || ! str_contains($doc->getText(), '@var')) {\n            return;\n        }\n\n        $extracted = DocblockExtractor::extractVarTagFromDoc($doc->getText());\n        if ($extracted === null) {\n            return;\n        }\n\n        [$typeString, $varName] = $extracted;\n        $isApplicable = ($varName === '')\n            || ($node->expr instanceof Node\\Expr\\Variable && $node->expr->name === $varName);\n\n        if ($isApplicable) {\n            $node->expr = $this->wrapVariableCheck(\n                $node->expr,\n                $typeString,\n                $varName !== '' ? $varName : 'return',\n                $node->getStartLine()\n            );\n            $node->setAttribute('typephp_var_wrapped', true);\n        }\n    }\n\n    /**\n     * @return array<Node>|null\n     */\n    private function handleExpression(Node\\Stmt\\Expression $node): ?array\n    {\n        $doc = $node->getDocComment();\n        if ($doc !== null && str_contains($doc->getText(), '@var')) {\n            $this->scopeManager->extractVarDocblock($doc->getText(), $node->expr);\n        }\n\n        if (! ($node->expr instanceof Node\\Expr\\Assign) || ! $this->isDestructuring($node->expr->var)) {\n            return null;\n        }\n\n        /** @var Node\\Expr\\List_|Node\\Expr\\Array_ $destructuringVar */\n        $destructuringVar = $node->expr->var;\n        $destructuredVars = $this->extractDestructuringVariables($destructuringVar);\n        $checkStmts = [];\n\n        foreach ($destructuredVars as $dVar) {\n            $varName = $dVar['varName'];\n            $typeString = $this->scopeManager->getVarTypeFromScope($varName);\n\n            if ($typeString !== null) {\n                $checkStmt = new Node\\Stmt\\Expression(\n                    new Node\\Expr\\Assign(\n                        $dVar['expr'],\n                        $this->wrapVariableCheck($dVar['expr'], $typeString, $varName, $dVar['expr']->getStartLine())\n                    )\n                );\n                $checkStmt->setAttribute('typephp_injected', true);\n                $checkStmts[] = $checkStmt;\n            }\n        }\n\n        return $checkStmts !== [] ? [$node, ...$checkStmts] : null;\n    }\n\n    private function handleAssign(Node\\Expr\\Assign $node): void\n    {\n        if ($node->var instanceof Node\\Expr\\Variable && \\is_string($node->var->name)) {\n            $varName = $node->var->name;\n            $typeString = $this->scopeManager->getVarTypeFromScope($varName);\n\n            if ($typeString !== null) {\n                $expr = $node->expr;\n                if ($expr instanceof Node\\Expr\\New_ && str_contains($typeString, '<')) {\n                    $expr = new Node\\Expr\\StaticCall(\n                        new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker'),\n                        'withPendingGeneric',\n                        [\n                            new Node\\Arg(new Node\\Scalar\\String_($typeString)),\n                            new Node\\Arg(new Node\\Expr\\ArrowFunction([\n                                'expr' => $expr,\n                            ])),\n                            new Node\\Arg(new Node\\Scalar\\MagicConst\\File()),\n                        ]\n                    );\n                }\n\n                $node->expr = $this->wrapVariableCheck($expr, $typeString, $varName, $node->var->getStartLine());\n            }\n        } elseif ($node->var instanceof Node\\Expr\\PropertyFetch && $node->var->name instanceof Node\\Identifier) {\n            $node->expr = $this->wrapPropertyCheck($node->expr, $node->var->var, $node->var->name->toString(), $node->var->getStartLine());\n        } elseif ($node->var instanceof Node\\Expr\\StaticPropertyFetch && $node->var->name instanceof Node\\VarLikeIdentifier) {\n            $classArg = $node->var->class instanceof Node\\Name\n                ? new Node\\Expr\\ClassConstFetch($node->var->class, 'class')\n                : $node->var->class;\n\n            $node->expr = $this->wrapPropertyCheck($node->expr, $classArg, $node->var->name->toString(), $node->var->getStartLine());\n        }\n    }\n\n    private function handleAssignOp(Node\\Expr\\AssignOp $node): ?Node\\Expr\\Assign\n    {\n        $binaryOpClass = self::ASSIGN_OP_MAP[$node::class] ?? null;\n        if ($binaryOpClass === null) {\n            return null;\n        }\n\n        $binaryExpr = new $binaryOpClass($node->var, $node->expr);\n\n        if ($node->var instanceof Node\\Expr\\Variable && \\is_string($node->var->name)) {\n            $varName = $node->var->name;\n            $typeString = $this->scopeManager->getVarTypeFromScope($varName);\n\n            if ($typeString !== null) {\n                return new Node\\Expr\\Assign(\n                    $node->var,\n                    $this->wrapVariableCheck($binaryExpr, $typeString, $varName, $node->var->getStartLine())\n                );\n            }\n        } elseif ($node->var instanceof Node\\Expr\\PropertyFetch && $node->var->name instanceof Node\\Identifier) {\n            return new Node\\Expr\\Assign(\n                $node->var,\n                $this->wrapPropertyCheck($binaryExpr, $node->var->var, $node->var->name->toString(), $node->var->getStartLine())\n            );\n        } elseif ($node->var instanceof Node\\Expr\\StaticPropertyFetch && $node->var->name instanceof Node\\VarLikeIdentifier) {\n            $classArg = $node->var->class instanceof Node\\Name\n                ? new Node\\Expr\\ClassConstFetch($node->var->class, 'class')\n                : $node->var->class;\n\n            return new Node\\Expr\\Assign(\n                $node->var,\n                $this->wrapPropertyCheck($binaryExpr, $classArg, $node->var->name->toString(), $node->var->getStartLine())\n            );\n        }\n\n        return null;\n    }\n\n    private function handleIncDec(Node\\Expr\\PreInc|Node\\Expr\\PostInc|Node\\Expr\\PreDec|Node\\Expr\\PostDec $node): ?Node\\Expr\\Assign\n    {\n        $isInc = $node instanceof Node\\Expr\\PreInc || $node instanceof Node\\Expr\\PostInc;\n        $binaryClass = $isInc ? Node\\Expr\\BinaryOp\\Plus::class : Node\\Expr\\BinaryOp\\Minus::class;\n        $binaryExpr = new $binaryClass($node->var, new Node\\Scalar\\LNumber(1));\n\n        if ($node->var instanceof Node\\Expr\\Variable && \\is_string($node->var->name)) {\n            $varName = $node->var->name;\n            $typeString = $this->scopeManager->getVarTypeFromScope($varName);\n\n            if ($typeString !== null) {\n                return new Node\\Expr\\Assign(\n                    $node->var,\n                    $this->wrapVariableCheck($binaryExpr, $typeString, $varName, $node->var->getStartLine())\n                );\n            }\n        } elseif ($node->var instanceof Node\\Expr\\PropertyFetch && $node->var->name instanceof Node\\Identifier) {\n            return new Node\\Expr\\Assign(\n                $node->var,\n                $this->wrapPropertyCheck($binaryExpr, $node->var->var, $node->var->name->toString(), $node->var->getStartLine())\n            );\n        } elseif ($node->var instanceof Node\\Expr\\StaticPropertyFetch && $node->var->name instanceof Node\\VarLikeIdentifier) {\n            $classArg = $node->var->class instanceof Node\\Name\n                ? new Node\\Expr\\ClassConstFetch($node->var->class, 'class')\n                : $node->var->class;\n\n            return new Node\\Expr\\Assign(\n                $node->var,\n                $this->wrapPropertyCheck($binaryExpr, $classArg, $node->var->name->toString(), $node->var->getStartLine())\n            );\n        }\n\n        return null;\n    }\n\n    private function wrapVariableCheck(Node\\Expr $expr, string $typeString, string $varName, int $line): Node\\Expr\\Ternary\n    {\n        $checkCall = NodeBuilder::createVariableCheckCall(\n            $expr,\n            $typeString,\n            $varName,\n            $this->getCurrentCallerExpr(),\n            $this->getCurrentThisExpr()\n        );\n\n        return NodeBuilder::createTernaryThrowExpr($checkCall, $line);\n    }\n\n    private function wrapPropertyCheck(Node\\Expr $valueExpr, Node\\Expr $targetExpr, string $propName, int $line): Node\\Expr\\Ternary\n    {\n        $checkCall = NodeBuilder::createPropertyCheckCall($valueExpr, $targetExpr, $propName);\n\n        return NodeBuilder::createTernaryThrowExpr($checkCall, $line);\n    }\n\n    private function wrapClone(Node\\Expr\\Clone_ $node): ?Node\\Expr\\FuncCall\n    {\n        if ($node->getAttribute('typephp_wrapped') === true) {\n            return null;\n        }\n\n        $node->setAttribute('typephp_wrapped', true);\n\n        return new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::cloneInstance'),\n            [\n                new Node\\Arg(\n                    new Node\\Expr\\Clone_(\n                        new Node\\Expr\\FuncCall(\n                            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::prepareClone'),\n                            [new Node\\Arg($node->expr)]\n                        )\n                    )\n                ),\n                new Node\\Arg($node->expr),\n            ]\n        );\n    }\n\n    private function isScopeBoundary(Node $node): bool\n    {\n        return $node instanceof Node\\Stmt\\Function_\n            || $node instanceof Node\\Stmt\\ClassMethod\n            || $node instanceof Node\\Expr\\Closure\n            || $node instanceof Node\\Expr\\ArrowFunction\n            || $node instanceof Node\\Stmt\\If_\n            || $node instanceof Node\\Stmt\\Else_\n            || $node instanceof Node\\Stmt\\ElseIf_\n            || $node instanceof Node\\Stmt\\Foreach_\n            || $node instanceof Node\\Stmt\\While_\n            || $node instanceof Node\\Stmt\\For_\n            || $node instanceof Node\\Stmt\\Do_\n            || $node instanceof Node\\Stmt\\TryCatch;\n    }\n\n    private function isDestructuring(Node\\Expr $expr): bool\n    {\n        return $expr instanceof Node\\Expr\\List_\n            || ($expr instanceof Node\\Expr\\Array_ && $expr->getAttribute('kind') === Node\\Expr\\Array_::KIND_SHORT);\n    }\n\n    private function resolveQualifiedName(?Node\\Identifier $name): ?string\n    {\n        if ($name === null) {\n            return null;\n        }\n\n        return $this->currentNamespace !== ''\n            ? $this->currentNamespace . '\\\\' . $name->toString()\n            : $name->toString();\n    }\n\n    private function getCurrentCallerExpr(): Node\\Expr\n    {\n        if ($this->methodStack !== [] && $this->classStack !== []) {\n            $classInfo = end($this->classStack);\n            $methodInfo = end($this->methodStack);\n\n            if (! $classInfo['isAnonymous'] && $classInfo['name'] !== null) {\n                return new Node\\Scalar\\String_($classInfo['name'] . '::' . $methodInfo['name']);\n            }\n\n            return new Node\\Expr\\BinaryOp\\Concat(\n                new Node\\Scalar\\MagicConst\\Class_(),\n                new Node\\Scalar\\String_('::' . $methodInfo['name'])\n            );\n        }\n\n        if ($this->functionStack !== []) {\n            return new Node\\Scalar\\String_(end($this->functionStack));\n        }\n\n        return new Node\\Scalar\\String_('');\n    }\n\n    private function getCurrentThisExpr(): Node\\Expr\n    {\n        $hasThis = $this->classStack !== []\n            && $this->thisAvailableStack !== []\n            && end($this->thisAvailableStack);\n\n        return $hasThis\n            ? new Node\\Expr\\Variable('this')\n            : new Node\\Expr\\ConstFetch(new Node\\Name('null'));\n    }\n\n    /**\n     * Recursively extracts target variables assigned inside a list() or [] destructuring node.\n     *\n     * @return list<array{varName: string, expr: Node\\Expr\\Variable}>\n     */\n    private function extractDestructuringVariables(Node\\Expr\\List_|Node\\Expr\\Array_ $listNode): array\n    {\n        $vars = [];\n        foreach ($listNode->items as $item) {\n            if ($item === null) {\n                continue;\n            }\n\n            if ($item->value instanceof Node\\Expr\\Variable && \\is_string($item->value->name)) {\n                $vars[] = [\n                    'varName' => $item->value->name,\n                    'expr' => $item->value,\n                ];\n            } elseif ($item->value instanceof Node\\Expr\\List_ || $item->value instanceof Node\\Expr\\Array_) {\n                $vars = [...$vars, ...$this->extractDestructuringVariables($item->value)];\n            }\n        }\n\n        return $vars;\n    }\n}\n","/typephp/src/Internal/Ast/FunctionContractInjector.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Comment\\Doc;\nuse PhpParser\\Node;\nuse PhpParser\\NodeTraverser;\nuse PhpParser\\NodeVisitorAbstract;\n\n/**\n * @internal Injects parameter checks, return checks, param-out checks, and generator interceptors into functions and methods.\n */\nfinal class FunctionContractInjector\n{\n    private const ITERABLE_TYPES = [\n        'iterable' => true,\n        'traversable' => true,\n        'generator' => true,\n        'iterator' => true,\n        'iteratoraggregate' => true,\n    ];\n\n    private const CALLABLE_TYPES = [\n        'callable' => true,\n        'closure' => true,\n    ];\n\n    /**\n     * @param array{hasInheritance?: bool, hasRealInheritance?: bool, hasPropertyWithDoc?: bool, isReadonly?: bool, hasTemplates?: bool}|null $classContext\n     */\n    public static function inject(Node\\Stmt\\Function_|Node\\Stmt\\ClassMethod $node, ?array $classContext = null): void\n    {\n        if ($node->stmts === null) {\n            return;\n        }\n\n        $isClassMethod = $node instanceof Node\\Stmt\\ClassMethod;\n        $doc = self::resolveDocComment($node);\n        $docText = $doc !== null ? $doc->getText() : '';\n\n        $hasInheritance = $classContext['hasInheritance'] ?? true;\n        $hasRealInheritance = $classContext['hasRealInheritance'] ?? $hasInheritance;\n        $hasPropertyWithDoc = $classContext['hasPropertyWithDoc'] ?? true;\n        $isReadonlyClass = $classContext['isReadonly'] ?? false;\n        $hasClassTemplates = $classContext['hasTemplates'] ?? false;\n\n        $methodName = $isClassMethod ? strtolower($node->name->toString()) : '';\n        $isConstructor = $isClassMethod && $methodName === '__construct';\n        $isMagicLifecycle = $isClassMethod && \\in_array($methodName, ['__construct', '__destruct', '__clone'], true);\n        $isNativeNever = $node->returnType instanceof Node\\Identifier && strtolower($node->returnType->name) === 'never';\n        $isNativeVoid = $node->returnType instanceof Node\\Identifier && strtolower($node->returnType->name) === 'void';\n        $isPrivate = $isClassMethod && $node->isPrivate();\n\n        $paramCount = \\count($node->params);\n\n        $hasParam = self::hasParamContracts(\n            $docText,\n            $isClassMethod,\n            $hasInheritance,\n            $paramCount,\n            $isPrivate,\n            $isConstructor,\n            $hasPropertyWithDoc,\n            $classContext === null,\n            $node->attrGroups !== []\n        );\n\n        $byRefParams = [];\n        foreach ($node->params as $p) {\n            if ($p->byRef && $p->var instanceof Node\\Expr\\Variable && \\is_string($p->var->name)) {\n                $byRefParams[] = $p->var->name;\n            }\n        }\n\n        $hasParamOutDoc = str_contains($docText, '@param-out')\n            || str_contains($docText, '@phpstan-param-out')\n            || str_contains($docText, '@psalm-param-out');\n\n        $hasParamOut = $byRefParams !== [] && ($hasParamOutDoc || $hasInheritance);\n\n        $hasSelfOutDoc = str_contains($docText, 'self-out') || str_contains($docText, 'this-out');\n        $hasSelfOut = $isClassMethod && ! $node->isStatic() && ($hasSelfOutDoc || ($hasClassTemplates && $hasRealInheritance));\n\n        $hasReturnDoc = str_contains($docText, '@return')\n            || str_contains($docText, '@phpstan-return')\n            || str_contains($docText, '@psalm-return');\n\n        $hasReturn = ! $isMagicLifecycle\n            && ! $isNativeNever\n            && ! ($isNativeVoid && ! $hasReturnDoc)\n            && self::hasReturnContracts($docText, $isClassMethod, $isPrivate);\n\n        if (! $hasParam && ! $hasReturn && ! $hasParamOut && ! $hasSelfOut) {\n            return;\n        }\n\n        $thisArg = self::resolveThisArg($isClassMethod, $node);\n        $needsReturnVars = $hasParam && ($paramCount > 0) && (\n            $hasInheritance || str_contains($docText, ' is ') || ($hasReturnDoc && str_contains($docText, '$'))\n        );\n\n        $injectedStmts = [];\n        if ($hasParam) {\n            $injectedStmts = self::buildParamInjections($node->params, $docText, $thisArg, $isReadonlyClass);\n        }\n\n        if ($hasReturn || $hasParamOut || $hasSelfOut) {\n            $node->stmts = self::isGenerator($node)\n                ? self::wrapGeneratorReturns($node->stmts, $thisArg)\n                : self::wrapNonGeneratorReturns(\n                    $node->stmts,\n                    $thisArg,\n                    $isNativeVoid,\n                    $needsReturnVars,\n                    $hasReturn,\n                    $hasParamOut ? $byRefParams : [],\n                    $hasSelfOut\n                );\n        }\n\n        $node->stmts = [...$injectedStmts, ...$node->stmts];\n    }\n\n    public static function buildSelfOutCheckStmt(Node\\Expr $thisArg, bool $needsReturnVars = false): Node\\Stmt\\Expression\n    {\n        $varsArg = $needsReturnVars\n            ? new Node\\Expr\\Variable('_typephpArgs')\n            : new Node\\Expr\\Array_();\n\n        $checkCall = new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::checkSelfOut'),\n            [\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                new Node\\Arg($thisArg),\n                new Node\\Arg($varsArg),\n            ]\n        );\n\n        $stmt = new Node\\Stmt\\Expression($checkCall);\n        $stmt->setAttribute('typephp_injected', true);\n\n        return $stmt;\n    }\n\n    private static function resolveDocComment(Node\\Stmt\\Function_|Node\\Stmt\\ClassMethod $node): ?Doc\n    {\n        $doc = $node->getDocComment();\n        if ($doc !== null) {\n            return $doc;\n        }\n\n        if ($node->attrGroups !== []) {\n            foreach ($node->attrGroups as $group) {\n                $groupDoc = $group->getDocComment();\n                if ($groupDoc !== null) {\n                    return $groupDoc;\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private static function hasParamContracts(\n        string $docText,\n        bool $isClassMethod,\n        bool $hasInheritance,\n        int $paramCount,\n        bool $isPrivate,\n        bool $isConstructor,\n        bool $hasPropertyWithDoc,\n        bool $isDirectUnitTest,\n        bool $hasAttributes = false\n    ): bool {\n        if ($paramCount === 0 && ! str_contains($docText, '@template')) {\n            return $isDirectUnitTest && $isClassMethod;\n        }\n\n        if ($isDirectUnitTest && $isClassMethod) {\n            return true;\n        }\n\n        if ($isConstructor && $docText === '' && ! $hasPropertyWithDoc) {\n            return false;\n        }\n\n        if ($isPrivate && $docText === '') {\n            return false;\n        }\n\n        if (! $hasInheritance && $docText === '' && ! ($isConstructor && $hasPropertyWithDoc) && ! $hasAttributes) {\n            return false;\n        }\n\n        if (str_contains($docText, '@template') || str_contains($docText, '@phpstan-param') || str_contains($docText, '@psalm-param')) {\n            return true;\n        }\n\n        if (str_contains($docText, '@param')) {\n            return self::hasNonMixedParam($docText);\n        }\n\n        return $isClassMethod && ! $isPrivate;\n    }\n\n    private static function hasNonMixedParam(string $docText): bool\n    {\n        if ((int) preg_match_all('/@param\\s+([^\\s$]+)/', $docText, $matches) === 0) {\n            return false;\n        }\n\n        foreach ($matches[1] as $typeStr) {\n            $unionParts = explode('|', $typeStr);\n            $hasMixed = false;\n            foreach ($unionParts as $part) {\n                if (strtolower(trim($part)) === 'mixed') {\n                    $hasMixed = true;\n\n                    break;\n                }\n            }\n            if (! $hasMixed) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private static function hasReturnContracts(\n        string $docText,\n        bool $isClassMethod,\n        bool $isPrivate\n    ): bool {\n        if ($isPrivate && $docText === '') {\n            return false;\n        }\n\n        if (\n            str_contains($docText, '@template')\n            || str_contains($docText, '@phpstan-return')\n            || str_contains($docText, '@psalm-return')\n            || str_contains($docText, '$this')\n        ) {\n            return true;\n        }\n\n        if (preg_match('/@return\\s+([^\\s]+)/', $docText, $matches) === 1) {\n            $returnTypeStr = $matches[1];\n            $unionParts = explode('|', $returnTypeStr);\n            foreach ($unionParts as $part) {\n                if (strtolower(trim($part)) === 'mixed') {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        return $isClassMethod && ! $isPrivate;\n    }\n\n    private static function resolveThisArg(bool $isClassMethod, Node\\Stmt\\Function_|Node\\Stmt\\ClassMethod $node): Node\\Expr\n    {\n        if (! $isClassMethod) {\n            return new Node\\Expr\\ConstFetch(new Node\\Name('null'));\n        }\n\n        /** @var Node\\Stmt\\ClassMethod $node */\n        return $node->isStatic()\n            ? new Node\\Expr\\ClassConstFetch(new Node\\Name('static'), 'class')\n            : new Node\\Expr\\Variable('this');\n    }\n\n    private static function isGenerator(Node\\Stmt\\Function_|Node\\Stmt\\ClassMethod $node): bool\n    {\n        $visitor = new class () extends NodeVisitorAbstract {\n            public bool $isGen = false;\n\n            public function enterNode(Node $n): ?int\n            {\n                if ($n instanceof Node\\Expr\\Closure || $n instanceof Node\\Expr\\ArrowFunction || $n instanceof Node\\Stmt\\Function_ || $n instanceof Node\\Stmt\\ClassMethod) {\n                    return NodeTraverser::DONT_TRAVERSE_CHILDREN;\n                }\n\n                if ($n instanceof Node\\Expr\\Yield_ || $n instanceof Node\\Expr\\YieldFrom) {\n                    $this->isGen = true;\n\n                    return NodeTraverser::STOP_TRAVERSAL;\n                }\n\n                return null;\n            }\n        };\n\n        $traverser = new NodeTraverser();\n        $traverser->addVisitor($visitor);\n        /** @var array<Node\\Stmt> $stmts */\n        $stmts = $node->stmts;\n        $traverser->traverse($stmts);\n\n        return $visitor->isGen;\n    }\n\n    /**\n     * @param array<Node\\Param> $params\n     *\n     * @return array<Node\\Stmt>\n     */\n    private static function buildParamInjections(\n        array $params,\n        string $docText,\n        Node\\Expr $thisArg,\n        bool $isReadonlyClass = false\n    ): array {\n        $injectedStmts = [self::buildSetupScopeStmt($params, $thisArg)];\n        $callableWrappers = self::buildParamWrappers($params, $docText, $thisArg, [self::class, 'isCallableCandidate'], 'wrapCallable', $isReadonlyClass);\n        $iterableWrappers = self::buildParamWrappers($params, $docText, $thisArg, [self::class, 'isIterableCandidate'], 'wrapIterable', $isReadonlyClass);\n\n        return [...$injectedStmts, ...$callableWrappers, ...$iterableWrappers];\n    }\n\n    /**\n     * @param array<Node\\Param> $params\n     */\n    private static function buildSetupScopeStmt(array $params, Node\\Expr $thisArg): Node\\Stmt\\If_\n    {\n        $arrayItems = [];\n        foreach ($params as $param) {\n            if ($param->var instanceof Node\\Expr\\Variable && \\is_string($param->var->name)) {\n                $pName = $param->var->name;\n                $arrayItems[] = new Node\\ArrayItem(\n                    new Node\\Expr\\Variable($pName),\n                    new Node\\Scalar\\String_($pName)\n                );\n            }\n        }\n\n        $argsAssign = new Node\\Stmt\\Expression(\n            new Node\\Expr\\Assign(\n                new Node\\Expr\\Variable('_typephpArgs'),\n                new Node\\Expr\\Array_($arrayItems)\n            )\n        );\n\n        $checkCall = new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::setupScope'),\n            [\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                new Node\\Arg(new Node\\Expr\\Variable('_typephpArgs')),\n                new Node\\Arg($thisArg),\n            ]\n        );\n\n        $throwStmt = self::buildTypeErrorThrowStmt(new Node\\Expr\\Variable('__typephpErr'));\n\n        $cacheKeyExpr = new Node\\Scalar\\MagicConst\\Method();\n\n        $noParamFetch = new Node\\Expr\\StaticPropertyFetch(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\Checker\\ParamChecker'),\n            'noParamContractCache'\n        );\n        $noParamFetch->setAttribute('typephp_checked', true);\n\n        $noParamCacheCheck = new Node\\Expr\\BooleanNot(\n            new Node\\Expr\\Isset_([\n                new Node\\Expr\\ArrayDimFetch(\n                    $noParamFetch,\n                    $cacheKeyExpr\n                ),\n            ])\n        );\n\n        $hasTemplatesFetch = new Node\\Expr\\StaticPropertyFetch(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker'),\n            'hasMethodTemplatesCache'\n        );\n        $hasTemplatesFetch->setAttribute('typephp_checked', true);\n\n        $hasTemplatesCheck = new Node\\Expr\\BinaryOp\\Coalesce(\n            new Node\\Expr\\ArrayDimFetch(\n                $hasTemplatesFetch,\n                $cacheKeyExpr\n            ),\n            new Node\\Expr\\ConstFetch(new Node\\Name('false'))\n        );\n\n        $combinedCondition = new Node\\Expr\\BinaryOp\\BooleanOr($noParamCacheCheck, $hasTemplatesCheck);\n\n        $ifStmt = new Node\\Stmt\\If_(\n            $combinedCondition,\n            [\n                'stmts' => [\n                    $argsAssign,\n                    new Node\\Stmt\\If_(\n                        new Node\\Expr\\Instanceof_(\n                            new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpErr'), $checkCall),\n                            new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n                        ),\n                        ['stmts' => [$throwStmt]]\n                    ),\n                ],\n            ]\n        );\n\n        $ifStmt->setAttribute('typephp_injected', true);\n\n        return $ifStmt;\n    }\n\n    /**\n     * @param array<string> $byRefParamNames\n     *\n     * @return array<Node\\Stmt>\n     */\n    public static function buildParamOutCheckStmts(array $byRefParamNames, Node\\Expr $thisArg): array\n    {\n        $stmts = [];\n        foreach ($byRefParamNames as $pName) {\n            $checkCall = new Node\\Expr\\FuncCall(\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::checkParamOut'),\n                [\n                    new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                    new Node\\Arg(new Node\\Scalar\\String_($pName)),\n                    new Node\\Arg(new Node\\Expr\\Variable($pName)),\n                    new Node\\Arg($thisArg),\n                ]\n            );\n\n            $ifStmt = new Node\\Stmt\\If_(\n                new Node\\Expr\\Instanceof_(\n                    new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpErr'), $checkCall),\n                    new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n                ),\n                ['stmts' => [self::buildTypeErrorThrowStmt(new Node\\Expr\\Variable('__typephpErr'))]]\n            );\n            $ifStmt->setAttribute('typephp_injected', true);\n            $stmts[] = $ifStmt;\n        }\n\n        return $stmts;\n    }\n\n    /**\n     * @param array<Node\\Param> $params\n     * @param callable(Node\\Param, string): bool $predicate\n     *\n     * @return array<Node\\Stmt>\n     */\n    private static function buildParamWrappers(\n        array $params,\n        string $docText,\n        Node\\Expr $thisArg,\n        callable $predicate,\n        string $wrapperMethod,\n        bool $isReadonlyClass = false\n    ): array {\n        $wrappers = [];\n\n        foreach ($params as $param) {\n            if ($predicate($param, $docText) && $param->var instanceof Node\\Expr\\Variable && \\is_string($param->var->name)) {\n                $paramName = $param->var->name;\n                $assignExpr = new Node\\Expr\\Assign(\n                    new Node\\Expr\\Variable($paramName),\n                    new Node\\Expr\\FuncCall(\n                        new Node\\Name\\FullyQualified(\"TypePHP\\Internal\\RuntimeTypeChecker::{$wrapperMethod}\"),\n                        [\n                            new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                            new Node\\Arg(new Node\\Scalar\\String_($paramName)),\n                            new Node\\Arg(new Node\\Expr\\Variable($paramName)),\n                            new Node\\Arg($thisArg),\n                        ]\n                    )\n                );\n\n                $expr = new Node\\Stmt\\Expression($assignExpr);\n                $expr->setAttribute('typephp_injected', true);\n                $wrappers[] = $expr;\n\n                $isReadonlyParam = ($param->flags & Node\\Stmt\\Class_::MODIFIER_READONLY) !== 0;\n                $isReadonly = $isReadonlyParam || $isReadonlyClass;\n\n                if ($param->isPromoted() && ! $isReadonly) {\n                    $propAssign = new Node\\Stmt\\Expression(\n                        new Node\\Expr\\Assign(\n                            new Node\\Expr\\PropertyFetch(new Node\\Expr\\Variable('this'), $paramName),\n                            new Node\\Expr\\Variable($paramName)\n                        )\n                    );\n                    $propAssign->setAttribute('typephp_injected', true);\n                    $wrappers[] = $propAssign;\n                }\n            }\n        }\n\n        return $wrappers;\n    }\n\n    private static function isCallableCandidate(Node\\Param $param, string $docText): bool\n    {\n        if (\n            str_contains($docText, 'callable')\n            || str_contains($docText, 'Closure')\n            || str_contains($docText, 'pure-callable')\n            || str_contains($docText, 'static-closure')\n        ) {\n            return true;\n        }\n\n        return self::typeMatchesName($param->type, self::CALLABLE_TYPES);\n    }\n\n    private static function isIterableCandidate(Node\\Param $param, string $docText): bool\n    {\n        if (self::typeMatchesName($param->type, self::ITERABLE_TYPES)) {\n            return true;\n        }\n\n        $paramName = $param->var instanceof Node\\Expr\\Variable && \\is_string($param->var->name) ? $param->var->name : '';\n        if ($paramName !== '' && preg_match('/@(?:param|phpstan-param|psalm-param)\\s+[^\\$]*?(?:iterable|Traversable|Generator|Iterator)\\b[^\\$]*?\\$' . preg_quote($paramName, '/') . '\\b/i', $docText) === 1) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * @param array<string, true> $targetNames\n     */\n    private static function typeMatchesName(Node\\Identifier|Node\\Name|Node\\ComplexType|null $type, array $targetNames): bool\n    {\n        if ($type instanceof Node\\Identifier) {\n            return isset($targetNames[strtolower($type->name)]);\n        }\n        if ($type instanceof Node\\Name) {\n            return isset($targetNames[strtolower($type->getLast())]);\n        }\n        if ($type instanceof Node\\UnionType || $type instanceof Node\\IntersectionType) {\n            foreach ($type->types as $t) {\n                if (self::typeMatchesName($t, $targetNames)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    public static function buildTypeErrorThrowExpr(Node\\Expr $errorVar, ?int $line = null): Node\\Expr\\Throw_\n    {\n        $args = [\n            new Node\\Arg(\n                new Node\\Expr\\New_(\n                    new Node\\Name\\FullyQualified('TypePHP\\Exception\\TypeError'),\n                    [\n                        new Node\\Arg(\n                            new Node\\Expr\\MethodCall($errorVar, 'getMessage')\n                        ),\n                    ]\n                )\n            ),\n        ];\n\n        if ($line !== null) {\n            $args[] = new Node\\Arg(new Node\\Scalar\\LNumber($line));\n        }\n\n        return new Node\\Expr\\Throw_(\n            new Node\\Expr\\StaticCall(\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorFactory'),\n                'prepareException',\n                $args\n            )\n        );\n    }\n\n    public static function buildTypeErrorThrowStmt(Node\\Expr $errorVar): Node\\Stmt\\Expression\n    {\n        return new Node\\Stmt\\Expression(self::buildTypeErrorThrowExpr($errorVar));\n    }\n\n    public static function buildReturnCheckCall(Node\\Expr $exprToWrap, Node\\Expr $thisArg, bool $needsReturnVars = false): Node\\Expr\\FuncCall\n    {\n        $varsArg = $needsReturnVars\n            ? new Node\\Expr\\Variable('_typephpArgs')\n            : new Node\\Expr\\Array_();\n\n        return new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::checkReturn'),\n            [\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                new Node\\Arg($exprToWrap),\n                new Node\\Arg($thisArg),\n                new Node\\Arg($varsArg),\n            ]\n        );\n    }\n\n    /**\n     * @return array<Node\\Stmt>\n     */\n    public static function buildVoidReturnGuard(Node\\Expr\\FuncCall $checkCall): array\n    {\n        $ifStmt = new Node\\Stmt\\If_(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpRet'), $checkCall),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            ['stmts' => [self::buildTypeErrorThrowStmt(new Node\\Expr\\Variable('__typephpRet'))]]\n        );\n        $ifStmt->setAttribute('typephp_injected', true);\n\n        $retStmt = new Node\\Stmt\\Return_(null);\n        $retStmt->setAttribute('typephp_injected', true);\n\n        return [$ifStmt, $retStmt];\n    }\n\n    public static function buildTernaryReturnExpr(Node\\Expr\\FuncCall $checkCall, ?int $line = null): Node\\Expr\\Ternary\n    {\n        return new Node\\Expr\\Ternary(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpRet'), $checkCall),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            self::buildTypeErrorThrowExpr(new Node\\Expr\\Variable('__typephpRet'), $line),\n            new Node\\Expr\\Variable('__typephpRet')\n        );\n    }\n\n    public static function buildWrappedYieldNode(Node\\Expr\\Yield_ $n, Node\\Expr $thisArg): Node\\Expr\\Ternary\n    {\n        $checkYieldCall = new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::checkYield'),\n            [\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                new Node\\Arg($n->key ?? new Node\\Expr\\ConstFetch(new Node\\Name('null'))),\n                new Node\\Arg($n->value ?? new Node\\Expr\\ConstFetch(new Node\\Name('null'))),\n                new Node\\Arg($thisArg),\n            ]\n        );\n\n        $n->value = new Node\\Expr\\Ternary(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpYld'), $checkYieldCall),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            self::buildTypeErrorThrowExpr(new Node\\Expr\\Variable('__typephpYld'), $n->getStartLine()),\n            new Node\\Expr\\Variable('__typephpYld')\n        );\n\n        $checkSendCall = new Node\\Expr\\FuncCall(\n            new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::checkSend'),\n            [\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                new Node\\Arg($n),\n                new Node\\Arg($thisArg),\n            ]\n        );\n\n        return new Node\\Expr\\Ternary(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpSnd'), $checkSendCall),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            self::buildTypeErrorThrowExpr(new Node\\Expr\\Variable('__typephpSnd')),\n            new Node\\Expr\\Variable('__typephpSnd')\n        );\n    }\n\n    /**\n     * @param array<Node\\Stmt> $stmts\n     *\n     * @return array<Node\\Stmt>\n     */\n    private static function wrapGeneratorReturns(array $stmts, Node\\Expr $thisArg): array\n    {\n        $traverser = new NodeTraverser();\n        $traverser->addVisitor(new class ($thisArg) extends NodeVisitorAbstract {\n            public function __construct(private Node\\Expr $thisArg)\n            {\n            }\n\n            public function enterNode(Node $n): int|Node|null\n            {\n                if ($n instanceof Node\\Expr\\Closure || $n instanceof Node\\Expr\\ArrowFunction || $n instanceof Node\\Stmt\\Function_ || $n instanceof Node\\Stmt\\ClassMethod) {\n                    return NodeTraverser::DONT_TRAVERSE_CHILDREN;\n                }\n\n                if ($n instanceof Node\\Expr\\Yield_) {\n                    if ($n->getAttribute('typephp_wrapped') === true) {\n                        return null;\n                    }\n                    $n->setAttribute('typephp_wrapped', true);\n\n                    return FunctionContractInjector::buildWrappedYieldNode($n, $this->thisArg);\n                }\n\n                if ($n instanceof Node\\Expr\\YieldFrom) {\n                    if ($n->getAttribute('typephp_wrapped') === true) {\n                        return null;\n                    }\n                    $n->setAttribute('typephp_wrapped', true);\n                    $n->expr = new Node\\Expr\\FuncCall(\n                        new Node\\Name\\FullyQualified('TypePHP\\Internal\\RuntimeTypeChecker::wrapIterable'),\n                        [\n                            new Node\\Arg(new Node\\Scalar\\MagicConst\\Method()),\n                            new Node\\Arg(new Node\\Scalar\\String_('return')),\n                            new Node\\Arg($n->expr),\n                            new Node\\Arg($this->thisArg),\n                        ]\n                    );\n                }\n\n                return null;\n            }\n        });\n\n        /** @var array<Node\\Stmt> $newStmts */\n        $newStmts = $traverser->traverse($stmts);\n\n        return $newStmts;\n    }\n\n    /**\n     * @param array<Node\\Stmt> $stmts\n     * @param array<string> $byRefParams\n     *\n     * @return array<Node\\Stmt>\n     */\n    private static function wrapNonGeneratorReturns(\n        array $stmts,\n        Node\\Expr $thisArg,\n        bool $isNativeVoid,\n        bool $needsReturnVars = false,\n        bool $hasReturn = true,\n        array $byRefParams = [],\n        bool $hasSelfOut = false\n    ): array {\n        $traverser = new NodeTraverser();\n        $traverser->addVisitor(new class ($thisArg, $isNativeVoid, $needsReturnVars, $hasReturn, $byRefParams, $hasSelfOut) extends NodeVisitorAbstract {\n            /**\n             * @param array<string> $byRefParams\n             */\n            public function __construct(\n                private Node\\Expr $thisArg,\n                private bool $isNativeVoid,\n                private bool $needsReturnVars,\n                private bool $hasReturn,\n                private array $byRefParams,\n                private bool $hasSelfOut\n            ) {\n            }\n\n            public function enterNode(Node $n): int|array|null\n            {\n                if ($n instanceof Node\\Expr\\Closure || $n instanceof Node\\Expr\\ArrowFunction || $n instanceof Node\\Stmt\\Function_ || $n instanceof Node\\Stmt\\ClassMethod) {\n                    return NodeTraverser::DONT_TRAVERSE_CHILDREN;\n                }\n\n                if ($n instanceof Node\\Stmt\\Return_) {\n                    if ($n->getAttribute('typephp_var_wrapped') === true) {\n                        return null;\n                    }\n\n                    $exitStmts = [];\n                    if ($this->hasSelfOut) {\n                        $exitStmts[] = FunctionContractInjector::buildSelfOutCheckStmt($this->thisArg, $this->needsReturnVars);\n                    }\n\n                    $paramOutStmts = $this->byRefParams !== []\n                        ? FunctionContractInjector::buildParamOutCheckStmts($this->byRefParams, $this->thisArg)\n                        : [];\n\n                    if ($paramOutStmts !== []) {\n                        $exitStmts = [...$exitStmts, ...$paramOutStmts];\n                    }\n\n                    if (! $this->hasReturn) {\n                        return $exitStmts !== [] ? [...$exitStmts, $n] : null;\n                    }\n\n                    $exprToWrap = $n->expr ?? new Node\\Expr\\ConstFetch(new Node\\Name('null'));\n\n                    if ($this->isNativeVoid) {\n                        $checkCall = FunctionContractInjector::buildReturnCheckCall($exprToWrap, $this->thisArg, $this->needsReturnVars);\n                        $voidGuardStmts = FunctionContractInjector::buildVoidReturnGuard($checkCall);\n\n                        return [...$exitStmts, ...$voidGuardStmts];\n                    }\n\n                    $checkCall = FunctionContractInjector::buildReturnCheckCall($exprToWrap, $this->thisArg, $this->needsReturnVars);\n                    $n->expr = FunctionContractInjector::buildTernaryReturnExpr($checkCall, $n->getStartLine());\n\n                    return $exitStmts !== [] ? [...$exitStmts, $n] : null;\n                }\n\n                return null;\n            }\n        });\n\n        /** @var array<Node\\Stmt> $newStmts */\n        $newStmts = $traverser->traverse($stmts);\n\n        $lastStmt = end($newStmts);\n        if (! $lastStmt instanceof Node\\Stmt\\Return_ && ! ($lastStmt instanceof Node\\Stmt\\Expression && $lastStmt->expr instanceof Node\\Expr\\Throw_)) {\n            $exitStmts = [];\n            if ($hasSelfOut) {\n                $exitStmts[] = self::buildSelfOutCheckStmt($thisArg, $needsReturnVars);\n            }\n\n            $paramOutStmts = $byRefParams !== []\n                ? self::buildParamOutCheckStmts($byRefParams, $thisArg)\n                : [];\n\n            if ($paramOutStmts !== []) {\n                $exitStmts = [...$exitStmts, ...$paramOutStmts];\n            }\n\n            if (! $hasReturn) {\n                if ($exitStmts !== []) {\n                    $newStmts = [...$newStmts, ...$exitStmts];\n                }\n            } else {\n                $checkCall = self::buildReturnCheckCall(new Node\\Expr\\ConstFetch(new Node\\Name('null')), $thisArg, $needsReturnVars);\n\n                if ($isNativeVoid) {\n                    $newStmts = [...$newStmts, ...$exitStmts, ...self::buildVoidReturnGuard($checkCall)];\n                } else {\n                    $fallbackLine = $lastStmt instanceof Node\\Stmt ? $lastStmt->getStartLine() : null;\n                    $ternaryExpr = self::buildTernaryReturnExpr($checkCall, $fallbackLine);\n\n                    $retStmt = new Node\\Stmt\\Return_($ternaryExpr);\n                    $retStmt->setAttribute('typephp_injected', true);\n                    $newStmts = [...$newStmts, ...$exitStmts, $retStmt];\n                }\n            }\n        }\n\n        return $newStmts;\n    }\n}\n","/typephp/src/Internal/Ast/NodeBuilder.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Node;\n\n/**\n * @internal Factory class building AST check nodes and ternary throw expressions.\n */\nfinal class NodeBuilder\n{\n    public static function createPropertyCheckCall(Node\\Expr $valueExpr, Node\\Expr $objectOrClassExpr, string $propertyName): Node\\Expr\\FuncCall\n    {\n        return new Node\\Expr\\FuncCall(\n            new Node\\Name('\\TypePHP\\Internal\\RuntimeTypeChecker::checkProperty'),\n            [\n                new Node\\Arg($valueExpr),\n                new Node\\Arg($objectOrClassExpr),\n                new Node\\Arg(new Node\\Scalar\\String_($propertyName)),\n                new Node\\Arg(new Node\\Scalar\\MagicConst\\File()),\n            ]\n        );\n    }\n\n    public static function createVariableCheckCall(\n        Node\\Expr $valueExpr,\n        string $typeString,\n        string $varName,\n        ?Node\\Expr $callerExpr = null,\n        ?Node\\Expr $thisArg = null\n    ): Node\\Expr\\FuncCall {\n        $args = [\n            new Node\\Arg($valueExpr),\n            new Node\\Arg(new Node\\Scalar\\String_($typeString)),\n            new Node\\Arg(new Node\\Scalar\\String_($varName)),\n            new Node\\Arg(new Node\\Scalar\\MagicConst\\File()),\n        ];\n\n        if ($callerExpr !== null) {\n            $args[] = new Node\\Arg($callerExpr);\n            if ($thisArg !== null) {\n                $args[] = new Node\\Arg($thisArg);\n            }\n        }\n\n        return new Node\\Expr\\FuncCall(\n            new Node\\Name('\\TypePHP\\Internal\\RuntimeTypeChecker::checkVariable'),\n            $args\n        );\n    }\n\n    public static function createTernaryThrowExpr(Node\\Expr\\FuncCall $checkCall, int $startLine = -1): Node\\Expr\\Ternary\n    {\n        $args = [\n            new Node\\Arg(\n                new Node\\Expr\\New_(\n                    new Node\\Name\\FullyQualified('TypePHP\\Exception\\TypeError'),\n                    [\n                        new Node\\Arg(\n                            new Node\\Expr\\MethodCall(\n                                new Node\\Expr\\Variable('__typephpVal'),\n                                'getMessage'\n                            )\n                        ),\n                    ]\n                )\n            ),\n        ];\n\n        if ($startLine !== -1) {\n            $args[] = new Node\\Arg(new Node\\Scalar\\LNumber($startLine));\n        }\n\n        return new Node\\Expr\\Ternary(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(\n                    new Node\\Expr\\Variable('__typephpVal'),\n                    $checkCall\n                ),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            new Node\\Expr\\Throw_(\n                new Node\\Expr\\StaticCall(\n                    new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorFactory'),\n                    'prepareException',\n                    $args\n                )\n            ),\n            new Node\\Expr\\Variable('__typephpVal')\n        );\n    }\n}\n","/typephp/src/Internal/Ast/PropertyHookInjector.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeTraverser;\nuse PhpParser\\NodeVisitorAbstract;\nuse TypePHP\\Internal\\Util\\Config;\n\n/**\n * @internal Injects property contract checks into PHP 8.4 get and set property hooks.\n */\nfinal class PropertyHookInjector\n{\n    public static function process(Node\\Stmt\\Property $node): void\n    {\n        if (self::shouldSkipInjection($node)) {\n            return;\n        }\n\n        $propertyName = $node->props[0]->name->toString();\n\n        foreach ($node->hooks as $hook) {\n            $hookName = strtolower($hook->name->toString());\n\n            if ($hookName === 'get') {\n                self::processGetHook($hook, $propertyName);\n            } elseif ($hookName === 'set') {\n                self::processSetHook($hook, $propertyName);\n            }\n        }\n    }\n\n    private static function shouldSkipInjection(Node\\Stmt\\Property $node): bool\n    {\n        if (! isset($node->hooks) || ! \\is_array($node->hooks) || $node->hooks === []) {\n            return true;\n        }\n\n        $doc = $node->getDocComment();\n        if ($doc === null) {\n            return false;\n        }\n\n        return Config::isRespectIgnoreTagsEnabled() && (str_contains($doc->getText(), '@typephp-ignore') || str_contains($doc->getText(), '@typephp-disable'));\n    }\n\n    private static function processGetHook(Node\\PropertyHook $hook, string $propertyName): void\n    {\n        if ($hook->body instanceof Node\\Expr) {\n            $checkCall = NodeBuilder::createPropertyCheckCall($hook->body, new Node\\Expr\\Variable('this'), $propertyName);\n            $hook->body = NodeBuilder::createTernaryThrowExpr($checkCall);\n        } elseif (\\is_array($hook->body)) {\n            $hook->body = self::wrapHookReturnStatements($hook->body, $propertyName);\n        }\n    }\n\n    private static function processSetHook(Node\\PropertyHook $hook, string $propertyName): void\n    {\n        $paramName = self::extractSetParamName($hook);\n        $checkCall = NodeBuilder::createPropertyCheckCall(new Node\\Expr\\Variable($paramName), new Node\\Expr\\Variable('this'), $propertyName);\n\n        if (\\is_array($hook->body)) {\n            $paramCheckStmt = new Node\\Stmt\\Expression(\n                new Node\\Expr\\Assign(\n                    new Node\\Expr\\Variable($paramName),\n                    NodeBuilder::createTernaryThrowExpr($checkCall)\n                )\n            );\n            $paramCheckStmt->setAttribute('typephp_injected', value: true);\n            array_unshift($hook->body, $paramCheckStmt);\n        } elseif ($hook->body instanceof Node\\Expr) {\n            $hook->body = self::buildExpressionSetHookTernary($checkCall, $hook->body);\n        }\n    }\n\n    private static function extractSetParamName(Node\\PropertyHook $hook): string\n    {\n        return ($hook->params !== [] && $hook->params[0]->var instanceof Node\\Expr\\Variable && \\is_string($hook->params[0]->var->name))\n            ? $hook->params[0]->var->name\n            : 'value';\n    }\n\n    private static function buildExpressionSetHookTernary(Node\\Expr\\FuncCall $checkCall, Node\\Expr $assignmentExpr): Node\\Expr\\Ternary\n    {\n        return new Node\\Expr\\Ternary(\n            new Node\\Expr\\Instanceof_(\n                new Node\\Expr\\Assign(new Node\\Expr\\Variable('__typephpVal'), $checkCall),\n                new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorMessage')\n            ),\n            new Node\\Expr\\Throw_(\n                new Node\\Expr\\StaticCall(\n                    new Node\\Name\\FullyQualified('TypePHP\\Internal\\Diagnostic\\ErrorFactory'),\n                    'prepareException',\n                    [\n                        new Node\\Arg(\n                            new Node\\Expr\\New_(\n                                new Node\\Name\\FullyQualified('TypePHP\\Exception\\TypeError'),\n                                [\n                                    new Node\\Arg(\n                                        new Node\\Expr\\MethodCall(new Node\\Expr\\Variable('__typephpVal'), 'getMessage')\n                                    ),\n                                ]\n                            )\n                        ),\n                    ]\n                )\n            ),\n            $assignmentExpr\n        );\n    }\n\n    /**\n     * @param array<Node\\Stmt> $stmts\n     *\n     * @return array<Node\\Stmt>\n     */\n    private static function wrapHookReturnStatements(array $stmts, string $propertyName): array\n    {\n        $traverser = new NodeTraverser();\n        $traverser->addVisitor(new class ($propertyName) extends NodeVisitorAbstract {\n            public function __construct(private string $propertyName)\n            {\n            }\n\n            public function enterNode(Node $node): int|null\n            {\n                if ($node instanceof Node\\Expr\\Closure || $node instanceof Node\\Expr\\ArrowFunction || $node instanceof Node\\Stmt\\Function_ || $node instanceof Node\\Stmt\\ClassMethod) {\n                    return NodeTraverser::DONT_TRAVERSE_CHILDREN;\n                }\n\n                if ($node instanceof Node\\Stmt\\Return_ && $node->expr !== null) {\n                    $checkCall = NodeBuilder::createPropertyCheckCall($node->expr, new Node\\Expr\\Variable('this'), $this->propertyName);\n                    $node->expr = NodeBuilder::createTernaryThrowExpr($checkCall);\n                }\n\n                return null;\n            }\n        });\n\n        /** @var array<Node\\Stmt> $newStmts */\n        $newStmts = $traverser->traverse($stmts);\n\n        return $newStmts;\n    }\n}\n","/typephp/src/Internal/Ast/ScopeCleaner.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse TypePHP\\Internal\\Generics\\TemplateManager;\n\n/**\n * @internal ensures proper scope cleanup for variable tracking.\n */\nfinal class ScopeCleaner\n{\n    public function __construct(private string $function)\n    {\n    }\n\n    public function __destruct()\n    {\n        TemplateManager::popCallFrame($this->function);\n    }\n}\n","/typephp/src/Internal/Ast/ScopeManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Node;\nuse TypePHP\\Internal\\Docblock\\DocblockExtractor;\n\n/**\n * @internal Manages lexical scope stack frames and extracts local @var variable annotations.\n */\nfinal class ScopeManager\n{\n    /**\n     * @var list<array<string, string>>\n     */\n    private array $scopeStack = [[]];\n\n    /**\n     * Tracks the current scope frame depth.\n     */\n    private int $depth = 0;\n\n    /**\n     * Pushes a new empty lexical scope frame (O(1)).\n     */\n    public function pushScope(): void\n    {\n        $this->depth++;\n        $this->scopeStack[] = [];\n    }\n\n    /**\n     * Pops the top scope frame, restoring the previous lexical scope (O(1)).\n     */\n    public function popScope(): void\n    {\n        if ($this->depth > 0) {\n            array_pop($this->scopeStack);\n            $this->depth--;\n        }\n    }\n\n    /**\n     * Extracts all @var tags from a docblock comment and registers them in the current scope frame.\n     * Prioritizes @phpstan-var > @psalm-var > @var.\n     */\n    public function extractVarDocblock(string $docText, ?Node\\Expr $expr = null): void\n    {\n        if (! str_contains($docText, 'var')) {\n            return;\n        }\n\n        try {\n            $phpDocNode = DocblockExtractor::parseDocString($docText);\n            $varTags = DocblockExtractor::getVarTags($phpDocNode);\n\n            foreach ($varTags as $varTag) {\n                $typeString = (string) $varTag->type;\n                $varName = ltrim($varTag->variableName, '$');\n\n                if ($varName === '' && $expr instanceof Node\\Expr\\Assign && $expr->var instanceof Node\\Expr\\Variable && \\is_string($expr->var->name)) {\n                    $varName = $expr->var->name;\n                } elseif ($varName === '' && $expr instanceof Node\\Expr\\Variable && \\is_string($expr->name)) {\n                    $varName = $expr->name;\n                }\n\n                if ($varName !== '') {\n                    $this->scopeStack[$this->depth][$varName] = $typeString;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed docblocks\n        }\n    }\n\n    /**\n     * Resolves a variable type by walking upward through the lexical scope chain.\n     */\n    public function getVarTypeFromScope(string $varName): ?string\n    {\n        for ($i = $this->depth; $i >= 0; $i--) {\n            if (isset($this->scopeStack[$i][$varName])) {\n                return $this->scopeStack[$i][$varName];\n            }\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Ast/TypePHPPrinter.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Ast;\n\nuse PhpParser\\Node;\nuse PhpParser\\PrettyPrinter\\Standard;\nuse PhpParser\\PrettyPrinterAbstract;\n\n/**\n * @internal\n *\n * Custom AST Printer that squashes injected TypePHP validation blocks into a single line\n * without adding trailing newlines to guarantee zero line-number drift.\n */\nfinal class TypePHPPrinter extends Standard\n{\n    /**\n     * Overrides base node printing to intercept injected statements, squash their\n     * formatting, and tag them with unique markers for post-processing.\n     */\n    protected function p(\n        Node $node,\n        int $precedence = PrettyPrinterAbstract::MAX_PRECEDENCE,\n        int $lhsPrecedence = PrettyPrinterAbstract::MAX_PRECEDENCE,\n        bool $parentFormatPreserved = false\n    ): string {\n        $output = parent::p($node, $precedence, $lhsPrecedence, $parentFormatPreserved);\n\n        if ($node instanceof Node\\Stmt && $node->getAttribute('typephp_injected') === true) {\n            $output = preg_replace('/(?:\\/\\/(.*?)|#(.*?))(?=\\r?\\n|$)/', '/*$1$2 */', $output) ?? $output;\n            $output = preg_replace('/\\s+/', ' ', trim($output)) ?? $output;\n\n            return '/*__TYPEPHP_INJECTED_START__*/' . $output . '/*__TYPEPHP_INJECTED_END__*/';\n        }\n\n        return $output;\n    }\n}\n","/typephp/src/Internal/Checker/ConditionalChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse ReflectionClass;\nuse Throwable;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Resolver\\HierarchyResolver;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @internal Evaluates parameter-based and template-based conditional types for parameters and returns.\n */\nfinal class ConditionalChecker\n{\n    /**\n     * Recursively resolves multi-branch nested conditional types ($param is Target ? A : B or T is Target ? A : B).\n     *\n     * @param array<int|string, mixed> $vars\n     * @param array<string, TypeNode> $boundTemplates\n     */\n    public static function resolve(\n        TypeNode $typeNode,\n        array $vars,\n        array $boundTemplates,\n        TypeValidatorRegistry $registry,\n        string $function = ''\n    ): TypeNode {\n        if ($typeNode instanceof ConditionalTypeForParameterNode) {\n            return self::resolveParameterConditional($typeNode, $vars, $boundTemplates, $registry, $function);\n        }\n\n        if ($typeNode instanceof ConditionalTypeNode) {\n            return self::resolveTemplateConditional($typeNode, $vars, $boundTemplates, $registry, $function);\n        }\n\n        return $typeNode;\n    }\n\n    /**\n     * Resolves parameter-based conditional types ($param is Target ? If : Else).\n     *\n     * @param array<int|string, mixed> $vars\n     * @param array<string, TypeNode> $boundTemplates\n     */\n    public static function resolveParameterConditional(\n        ConditionalTypeForParameterNode $node,\n        array $vars,\n        array $boundTemplates,\n        TypeValidatorRegistry $registry,\n        string $function = ''\n    ): TypeNode {\n        $paramName = ltrim($node->parameterName, '$');\n        $paramValue = null;\n\n        if (isset($vars[$paramName]) || \\array_key_exists($paramName, $vars)) {\n            $paramValue = $vars[$paramName];\n        } elseif (\\count($vars) > 0 && $function !== '' && str_contains($function, '::')) {\n            $paramValue = self::resolveRenamedParamValue($function, $paramName, $vars);\n        }\n\n        $targetErr = $registry->validate($paramValue, $node->targetType, 'condition');\n        $isTargetMatch = ($targetErr === null);\n        if ($node->negated) {\n            $isTargetMatch = ! $isTargetMatch;\n        }\n\n        $selectedBranch = $isTargetMatch ? $node->if : $node->else;\n\n        return self::resolve($selectedBranch, $vars, $boundTemplates, $registry, $function);\n    }\n\n    /**\n     * Resolves template-based conditional types (T is Target ? If : Else).\n     *\n     * @param array<int|string, mixed> $vars\n     * @param array<string, TypeNode> $boundTemplates\n     */\n    public static function resolveTemplateConditional(\n        ConditionalTypeNode $node,\n        array $vars,\n        array $boundTemplates,\n        TypeValidatorRegistry $registry,\n        string $function = ''\n    ): TypeNode {\n        $subjectTypeNode = $node->subjectType;\n        if ($subjectTypeNode instanceof IdentifierTypeNode && isset($boundTemplates[$subjectTypeNode->name])) {\n            $subjectTypeNode = $boundTemplates[$subjectTypeNode->name];\n        }\n\n        $isTargetMatch = TemplateManager::checkVariance($subjectTypeNode, $node->targetType, GenericTypeNode::VARIANCE_COVARIANT);\n        if ($node->negated) {\n            $isTargetMatch = ! $isTargetMatch;\n        }\n\n        $selectedBranch = $isTargetMatch ? $node->if : $node->else;\n\n        return self::resolve($selectedBranch, $vars, $boundTemplates, $registry, $function);\n    }\n\n    /**\n     * Disambiguates parameter value by positional index in method hierarchy when renamed in child class.\n     *\n     * @param array<int|string, mixed> $vars\n     */\n    private static function resolveRenamedParamValue(string $function, string $paramName, array $vars): mixed\n    {\n        [$className, $methodName] = explode('::', $function, 2);\n        if (! class_exists($className) && ! interface_exists($className) && ! trait_exists($className) && ! enum_exists($className)) {\n            return null;\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $refClass = new ReflectionClass($className);\n            if (! $refClass->hasMethod($methodName)) {\n                return null;\n            }\n\n            $refMethod = $refClass->getMethod($methodName);\n            $hierarchy = HierarchyResolver::getMethodHierarchy($refMethod);\n\n            $targetIndex = null;\n            foreach ($hierarchy as $hierMethod) {\n                foreach ($hierMethod->getParameters() as $idx => $p) {\n                    if ($p->getName() === $paramName) {\n                        $targetIndex = $idx;\n\n                        break 2;\n                    }\n                }\n            }\n\n            if ($targetIndex !== null) {\n                $values = array_values($vars);\n                if (isset($values[$targetIndex]) || \\array_key_exists($targetIndex, $values)) {\n                    return $values[$targetIndex];\n                }\n            }\n        } catch (Throwable $e) {\n            // Silently ignore reflection errors\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Checker/GeneratorChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @internal Evaluates generator yield and send (TSend) type validations.\n */\nfinal class GeneratorChecker\n{\n    /**\n     * O(1) Fast-path cache for generators determined to have no return contracts.\n     *\n     * @var array<string, true>\n     */\n    private static array $noContractCache = [];\n\n    /**\n     * Cache for resolved yield & send types of static / non-generic generators:\n     * [$function] => array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}.\n     *\n     * @var array<string, array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}>\n     */\n    private static array $staticYieldTypeCache = [];\n\n    /**\n     * 2D Cache for resolved yield & send types of generic generators:\n     * [$function][$templateSignature] => array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}.\n     *\n     * @var array<string, array<string, array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}>>\n     */\n    private static array $genericYieldTypeCache = [];\n\n    /**\n     * Validates a value sent into a generator via $gen->send() against TSend.\n     */\n    public static function checkSend(\n        string $function,\n        mixed $sendValue,\n        TypeValidatorRegistry $registry,\n        object|string|null $thisOrClass = null\n    ): mixed {\n        if ($sendValue === null) {\n            return null;\n        }\n\n        $types = self::resolveYieldAndSendTypes($function, $thisOrClass);\n        if ($types === null) {\n            return $sendValue;\n        }\n\n        $sendTypeNode = $types[2];\n        if ($sendTypeNode === null) {\n            return $sendValue;\n        }\n\n        $err = $registry->validate($sendValue, $sendTypeNode, \"$function(): Generator sent value (TSend)\");\n\n        return $err ?? $sendValue;\n    }\n\n    /**\n     * Validates yielded keys and values from a generator function against TKey and TValue with zero-allocation caching.\n     */\n    public static function checkYield(\n        string $function,\n        mixed $key,\n        mixed $value,\n        TypeValidatorRegistry $registry,\n        object|string|null $thisOrClass = null\n    ): mixed {\n        $types = self::resolveYieldAndSendTypes($function, $thisOrClass);\n        if ($types === null) {\n            return $value;\n        }\n\n        [$keyTypeNode, $itemTypeNode] = $types;\n\n        if ($key !== null && $keyTypeNode !== null) {\n            $err = $registry->validate($key, $keyTypeNode, \"$function(): Return iterator key\");\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        if ($itemTypeNode !== null) {\n            $err = $registry->validate($value, $itemTypeNode, \"$function(): Return iterator value\");\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        return $value;\n    }\n\n    /**\n     * Resolves and caches the generator's yielded key, value, and sent types in memory.\n     *\n     * @return array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}|null\n     */\n    private static function resolveYieldAndSendTypes(string $function, object|string|null $thisOrClass): ?array\n    {\n        if (isset(self::$noContractCache[$function])) {\n            return null;\n        }\n\n        if (isset(self::$staticYieldTypeCache[$function])) {\n            return self::$staticYieldTypeCache[$function];\n        }\n\n        $contract = DocblockParser::parse($function);\n        $returnTypeNode = $contract['return'] ?? null;\n\n        if ($returnTypeNode === null) {\n            self::$noContractCache[$function] = true;\n\n            return null;\n        }\n\n        $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n        $aliases = $contract['aliases'] ?? [];\n        $hasGenerics = \\count($allTemplates) > 0;\n        $hasAliases = \\count($aliases) > 0;\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        // Static / non-generic generator: cache permanently for this function\n        if (! $hasGenerics && ! $hasAliases && $thisObj === null) {\n            $resolvedNode = SpecialTypeResolver::resolve($returnTypeNode, $function, null);\n\n            return self::$staticYieldTypeCache[$function] = self::extractYieldTypes($resolvedNode);\n        }\n\n        // Generic generator: check signature-based 2D cache\n        $boundTemplates = $hasGenerics ? TemplateManager::getBoundTemplates($function, $thisObj, $allTemplates) : [];\n\n        $sig = null;\n        $boundCount = \\count($boundTemplates);\n        if ($boundCount > 0 && $boundCount <= 2 && ! $hasAliases && $thisObj === null) {\n            if ($boundCount === 1) {\n                $first = reset($boundTemplates);\n                $sig = $first instanceof IdentifierTypeNode ? $first->name : (string) $first;\n            } else {\n                $sig = '';\n                foreach ($boundTemplates as $v) {\n                    $sig .= ($v instanceof IdentifierTypeNode ? $v->name : (string) $v) . '|';\n                }\n            }\n\n            if (isset(self::$genericYieldTypeCache[$function][$sig])) {\n                return self::$genericYieldTypeCache[$function][$sig];\n            }\n        }\n\n        if ($returnTypeNode instanceof IdentifierTypeNode && isset($aliases[$returnTypeNode->name])) {\n            $returnTypeNode = $aliases[$returnTypeNode->name];\n        }\n\n        if (\\count($boundTemplates) > 0 || \\count($allTemplates) > 0) {\n            $returnTypeNode = TemplateSubstitutor::substitute($returnTypeNode, $boundTemplates, $allTemplates);\n            $returnTypeNode = SpecialTypeResolver::resolve($returnTypeNode, $function, $thisObj);\n        }\n\n        $types = self::extractYieldTypes($returnTypeNode);\n\n        if ($sig !== null) {\n            self::$genericYieldTypeCache[$function][$sig] = $types;\n        }\n\n        return $types;\n    }\n\n    /**\n     * Extracts yielded key, item, and sent (TSend) TypeNodes from a resolved generator/array AST node.\n     *\n     * @return array{0: ?TypeNode, 1: ?TypeNode, 2: ?TypeNode}\n     */\n    private static function extractYieldTypes(TypeNode $returnTypeNode): array\n    {\n        $itemTypeNode = null;\n        $keyTypeNode = null;\n        $sendTypeNode = null;\n\n        if ($returnTypeNode instanceof GenericTypeNode) {\n            $typesCount = \\count($returnTypeNode->genericTypes);\n            if ($typesCount === 1) {\n                $itemTypeNode = $returnTypeNode->genericTypes[0];\n            } elseif ($typesCount >= 2) {\n                $keyTypeNode = $returnTypeNode->genericTypes[0];\n                $itemTypeNode = $returnTypeNode->genericTypes[1];\n                $sendTypeNode = $returnTypeNode->genericTypes[2] ?? null;\n            }\n        } elseif ($returnTypeNode instanceof ArrayTypeNode) {\n            $itemTypeNode = $returnTypeNode->type;\n        }\n\n        return [$keyTypeNode, $itemTypeNode, $sendTypeNode];\n    }\n}\n","/typephp/src/Internal/Checker/InlineChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\Parser\\ConstExprParser;\nuse PHPStan\\PhpDocParser\\Parser\\TokenIterator;\nuse PHPStan\\PhpDocParser\\Parser\\TypeParser;\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse TypePHP\\Internal\\Docblock\\DocblockNormalizer;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\nuse TypePHP\\Internal\\Wrapper\\CallableWrapper;\n\n/**\n * Evaluates inline variable (@var) and class property validation rules.\n *\n * @internal\n */\nfinal class InlineChecker\n{\n    /**\n     * In-memory cache for tokenized and parsed TypeNode ASTs and their context necessity flag.\n     *\n     * @var array<string, array{0: TypeNode, 1: bool}>\n     */\n    private static array $parsedTypeNodeCache = [];\n\n    /**\n     * In-memory 3D cache for resolved class contexts with static bounds: [$className][$methodName][$typeString] => TypeNode.\n     *\n     * @var array<string, array<string, array<string, TypeNode>>>\n     */\n    private static array $resolvedClassContextCache = [];\n\n    /**\n     * In-memory 2D cache for properties known to have no DocBlock annotations: [$className][$propName] => true.\n     *\n     * @var array<string, array<string, true>>\n     */\n    public static array $nullPropertyCache = [];\n\n    /**\n     * Resets internal type node and function caches. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$parsedTypeNodeCache = [];\n        self::$resolvedClassContextCache = [];\n        self::$nullPropertyCache = [];\n    }\n\n    /**\n     * Fast lookup set for scalar refinement types.\n     */\n    private const SCALAR_TYPES = [\n        'int' => true,\n        'integer' => true,\n        'string' => true,\n        'bool' => true,\n        'boolean' => true,\n        'float' => true,\n        'double' => true,\n        'null' => true,\n        'true' => true,\n        'false' => true,\n        'scalar' => true,\n        'numeric' => true,\n        'positive-int' => true,\n        'negative-int' => true,\n        'non-positive-int' => true,\n        'non-negative-int' => true,\n        'non-zero-int' => true,\n        'unsigned-int' => true,\n        'positive-float' => true,\n        'negative-float' => true,\n        'non-positive-float' => true,\n        'non-negative-float' => true,\n        'non-zero-float' => true,\n        'non-empty-string' => true,\n        'numeric-string' => true,\n        'lowercase-string' => true,\n        'non-empty-lowercase-string' => true,\n        'uppercase-string' => true,\n        'non-empty-uppercase-string' => true,\n        'truthy' => true,\n        'falsy' => true,\n        'array-key' => true,\n    ];\n\n    /**\n     * Fast lookup set for iterable types.\n     */\n    private const ARRAY_TYPES = [\n        'array' => true,\n        'list' => true,\n        'iterable' => true,\n    ];\n\n    /**\n     * Evaluates inline variable validation dynamically based on configuration.\n     */\n    public static function checkVariable(\n        mixed $value,\n        string $typeString,\n        string $varName,\n        string $file,\n        TypeValidatorRegistry $registry,\n        ?string $caller = null,\n        mixed $thisOrClass = null\n    ): mixed {\n        if (! Config::hasActiveInlineChecks()) {\n            return $value;\n        }\n\n        try {\n            $normalized = DocblockNormalizer::normalize($typeString);\n            [$typeNode, $needsContext] = self::parseTypeString($normalized);\n\n            if ($file !== '') {\n                $typeNode = SpecialTypeResolver::resolveForFile($typeNode, $file);\n            }\n\n            if ($needsContext && $caller !== null) {\n                $typeNode = self::resolveCallerContext($typeNode, $caller, $thisOrClass);\n            }\n\n            if (! self::shouldValidateType($typeNode)) {\n                return $value;\n            }\n\n            if ($value === [] && $varName !== 'return' && self::isArrayShapeType($typeNode)) {\n                return $value;\n            }\n\n            $context = ($varName === 'return') ? 'Return value' : \"Variable \\$$varName\";\n\n            if ($typeNode instanceof CallableTypeNode || ($typeNode instanceof IdentifierTypeNode && strtolower($typeNode->name) === 'callable')) {\n                $cbPrefix = ($varName === 'return') ? 'Return value: Callback' : \"Variable \\$$varName: Callback\";\n\n                return CallableWrapper::wrapTypeNode($typeNode, $value, $cbPrefix, $registry);\n            }\n\n            if ($typeNode instanceof GenericTypeNode) {\n                $baseName = strtolower($typeNode->type->name);\n                $isCollection = isset(self::ARRAY_TYPES[$baseName]);\n\n                if (! $isCollection) {\n                    if (! Config::isInlineGenericsEnabled() && Config::isInlineObjectsEnabled()) {\n                        $typeNode = $typeNode->type;\n                    } elseif (! Config::isInlineGenericsEnabled() && ! Config::isInlineObjectsEnabled()) {\n                        return $value;\n                    }\n                }\n            }\n\n            if ($typeNode instanceof GenericTypeNode && Config::isInlineGenericsEnabled() && \\is_object($value)) {\n                $err = TemplateManager::bindInstanceFromNode($value, $typeNode, $context);\n                if ($err !== null) {\n                    return $err;\n                }\n            }\n\n            $err = $registry->validate($value, $typeNode, $context);\n            if ($err !== null) {\n                return $err;\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore unexpected execution exceptions\n        }\n\n        return $value;\n    }\n\n    /**\n     * Checks if a TypeNode is or contains an ArrayShapeNode.\n     */\n    private static function isArrayShapeType(TypeNode $node): bool\n    {\n        if ($node instanceof ArrayShapeNode) {\n            return true;\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return self::isArrayShapeType($node->type);\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            foreach ($node->types as $subType) {\n                if (self::isArrayShapeType($subType)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Evaluates class property validation dynamically based on configuration with zero-allocation 2D caching.\n     */\n    public static function checkProperty(mixed $value, mixed $objectOrClass, string $propName, string $file, TypeValidatorRegistry $registry): mixed\n    {\n        if (! \\is_object($objectOrClass) && ! \\is_string($objectOrClass)) {\n            return $value;\n        }\n\n        $className = \\is_string($objectOrClass) ? $objectOrClass : $objectOrClass::class;\n\n        if (isset(self::$nullPropertyCache[$className][$propName])) {\n            return $value;\n        }\n\n        if (! Config::isInlinePropertiesEnabled()) {\n            return $value;\n        }\n\n        $typeNode = DocblockParser::parseProperty($className, $propName);\n        if ($typeNode === null) {\n            self::$nullPropertyCache[$className][$propName] = true;\n\n            return $value;\n        }\n\n        if (! self::shouldValidateType($typeNode)) {\n            return $value;\n        }\n\n        if (\\is_object($objectOrClass)) {\n            $typeNode = self::substitutePropertyGenerics($typeNode, $objectOrClass, $className);\n        }\n\n        try {\n            $err = $registry->validate($value, $typeNode, 'Property ' . $className . '::$' . $propName);\n            if ($err !== null) {\n                return $err;\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore unexpected execution exceptions\n        }\n\n        return $value;\n    }\n\n    /**\n     * Resolves caller class or function context and applies templates & type aliases to the AST.\n     */\n    private static function resolveCallerContext(TypeNode $typeNode, ?string $caller = null, mixed $thisOrClass = null): TypeNode\n    {\n        if ($caller !== null) {\n            if ($caller === '') {\n                return $typeNode;\n            }\n\n            if (str_contains($caller, '::')) {\n                [$className, $methodName] = explode('::', $caller, 2);\n                $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n                return self::resolveClassContext(\n                    $typeNode,\n                    $className,\n                    $methodName,\n                    $thisObj\n                );\n            }\n\n            return self::resolveFunctionContext($typeNode, $caller);\n        }\n\n        return $typeNode;\n    }\n\n    /**\n     * Resolves templates and aliases within standalone functions.\n     */\n    private static function resolveFunctionContext(TypeNode $typeNode, string $functionName): TypeNode\n    {\n        if (! \\function_exists($functionName)) {\n            return $typeNode;\n        }\n\n        try {\n            $refFunc = new \\ReflectionFunction($functionName);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $refFunc);\n\n            $contract = DocblockParser::parse($functionName);\n            $declaredTemplates = $contract['templates'] ?? [];\n            $aliases = $contract['aliases'] ?? [];\n            $boundTemplates = TemplateManager::getBoundTemplates($functionName, null, $declaredTemplates);\n\n            $activeBindings = [...$aliases, ...$boundTemplates];\n\n            if (\\count($activeBindings) > 0 || \\count($declaredTemplates) > 0) {\n                $typeNode = TemplateSubstitutor::substitute($typeNode, $activeBindings, $declaredTemplates);\n                $typeNode = SpecialTypeResolver::resolve($typeNode, $refFunc);\n            }\n        } catch (\\ReflectionException $e) {\n            // Silently continue if reflection fails\n        }\n\n        return $typeNode;\n    }\n\n    /**\n     * Resolves templates, aliases, and class context within class methods using zero-allocation nested caching.\n     */\n    private static function resolveClassContext(\n        TypeNode $typeNode,\n        string $className,\n        ?string $methodName,\n        ?object $thisObj\n    ): TypeNode {\n        if (! class_exists($className) && ! interface_exists($className) && ! trait_exists($className)) {\n            return $typeNode;\n        }\n\n        $targetFunc = ($methodName !== '{closure}' && $methodName !== null && ! str_starts_with($methodName, '{closure'))\n            ? $className . '::' . $methodName\n            : $className . '::__construct';\n\n        $contract = DocblockParser::parse($targetFunc);\n        $hasMethodTemplates = ($contract['templates'] ?? []) !== [];\n\n        $methodKey = $methodName ?? '';\n        $typeString = null;\n        $canCache = ($thisObj === null && ! $hasMethodTemplates);\n\n        if ($canCache) {\n            $typeString = (string) $typeNode;\n            if (isset(self::$resolvedClassContextCache[$className][$methodKey][$typeString])) {\n                return self::$resolvedClassContextCache[$className][$methodKey][$typeString];\n            }\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $refClass = new \\ReflectionClass($className);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $refClass);\n\n            $classAliases = DocblockParser::parseClassAliases($className);\n            $allTemplates = $contract['allTemplates'] ?? [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n            $declaredTemplates = $allTemplates;\n\n            if ($classAliases === [] && $declaredTemplates === []) {\n                if ($canCache && $typeString !== null) {\n                    return self::$resolvedClassContextCache[$className][$methodKey][$typeString] = $typeNode;\n                }\n\n                return $typeNode;\n            }\n\n            $boundTemplates = TemplateManager::getBoundTemplates($targetFunc, $thisObj, $declaredTemplates);\n            $activeBindings = [...$classAliases, ...$boundTemplates];\n\n            if ($activeBindings !== [] || $declaredTemplates !== []) {\n                $typeNode = TemplateSubstitutor::substitute($typeNode, $activeBindings, $declaredTemplates);\n                $typeNode = SpecialTypeResolver::resolve($typeNode, $refClass);\n            }\n        } catch (\\ReflectionException $e) {\n            // Silently continue if reflection fails\n        }\n\n        if ($canCache && $typeString !== null) {\n            return self::$resolvedClassContextCache[$className][$methodKey][$typeString] = $typeNode;\n        }\n\n        return $typeNode;\n    }\n\n    /**\n     * Substitutes generic template types declared on class properties.\n     */\n    private static function substitutePropertyGenerics(TypeNode $typeNode, object $object, string $className): TypeNode\n    {\n        $constructorTarget = $className . '::__construct';\n        $contract = DocblockParser::parse($constructorTarget);\n\n        $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n        $boundTemplates = TemplateManager::getBoundTemplates('none', $object, $allTemplates);\n        $declaredTemplates = $allTemplates;\n\n        if (\\count($boundTemplates) > 0 || \\count($declaredTemplates) > 0) {\n            $typeNode = TemplateSubstitutor::substitute($typeNode, $boundTemplates, $declaredTemplates);\n\n            if (class_exists($className) || interface_exists($className) || trait_exists($className)) {\n                try {\n                    /** @var class-string<object> $className */\n                    $refClass = new \\ReflectionClass($className);\n                    $typeNode = SpecialTypeResolver::resolve($typeNode, $refClass);\n                } catch (\\ReflectionException $e) {\n                    // Silently continue if reflection fails\n                }\n            }\n        }\n\n        return $typeNode;\n    }\n\n    /**\n     * Inspects a TypeNode to check if it requires caller context resolution (templates, aliases, self/static/$this).\n     */\n    private static function needsContextResolution(TypeNode $node): bool\n    {\n        if ($node instanceof ThisTypeNode || $node instanceof OffsetAccessTypeNode || $node instanceof ConditionalTypeNode || $node instanceof ConditionalTypeForParameterNode) {\n            return true;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            $lower = strtolower($node->name);\n            if (\\in_array($lower, ['self', 'static', 'parent', '$this'], true)) {\n                return true;\n            }\n\n            return ! SpecialTypeResolver::isBuiltInTypeKeyword($lower);\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            return true;\n        }\n\n        if ($node instanceof ConstTypeNode) {\n            $constExpr = $node->constExpr;\n            if ($constExpr instanceof \\PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode && $constExpr->className !== '') {\n                return true;\n            }\n\n            return false;\n        }\n\n        if ($node instanceof NullableTypeNode || $node instanceof ArrayTypeNode) {\n            return self::needsContextResolution($node->type);\n        }\n\n        if ($node instanceof UnionTypeNode || $node instanceof IntersectionTypeNode) {\n            foreach ($node->types as $subType) {\n                if (self::needsContextResolution($subType)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            foreach ($node->items as $item) {\n                if (self::needsContextResolution($item->valueType)) {\n                    return true;\n                }\n            }\n\n            if ($node->unsealedType !== null) {\n                if ($node->unsealedType->keyType !== null && self::needsContextResolution($node->unsealedType->keyType)) {\n                    return true;\n                }\n\n                return self::needsContextResolution($node->unsealedType->valueType);\n            }\n\n            return false;\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            foreach ($node->items as $item) {\n                if (self::needsContextResolution($item->valueType)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            foreach ($node->parameters as $p) {\n                if (self::needsContextResolution($p->type)) {\n                    return true;\n                }\n            }\n\n            return self::needsContextResolution($node->returnType);\n        }\n\n        return false;\n    }\n\n    /**\n     * Parses and caches a type string into a TypeNode AST along with its context requirement flag.\n     *\n     * @return array{0: TypeNode, 1: bool}\n     */\n    private static function parseTypeString(string $typeString): array\n    {\n        if (isset(self::$parsedTypeNodeCache[$typeString])) {\n            return self::$parsedTypeNodeCache[$typeString];\n        }\n\n        [$typeParser, $lexer] = self::getTypeParserComponents();\n        $tokens = new TokenIterator($lexer->tokenize($typeString));\n        $typeNode = $typeParser->parse($tokens);\n        $needsContext = self::needsContextResolution($typeNode);\n\n        return self::$parsedTypeNodeCache[$typeString] = [$typeNode, $needsContext];\n    }\n\n    /**\n     * @return array{TypeParser, Lexer}\n     */\n    private static function getTypeParserComponents(): array\n    {\n        /** @var TypeParser|null $typeParser */\n        static $typeParser = null;\n        /** @var Lexer|null $lexer */\n        static $lexer = null;\n\n        if ($typeParser === null || $lexer === null) {\n            $configParser = new ParserConfig(usedAttributes: []);\n            $lexer = new Lexer($configParser);\n            $constExprParser = new ConstExprParser($configParser);\n            $typeParser = new TypeParser($configParser, $constExprParser);\n        }\n\n        return [$typeParser, $lexer];\n    }\n\n    private static function shouldValidateType(TypeNode $node): bool\n    {\n        $checkArrays = Config::isInlineArraysEnabled();\n\n        if ($node instanceof CallableTypeNode) {\n            return Config::isInlineCallablesEnabled();\n        }\n\n        if ($node instanceof ObjectShapeNode || $node instanceof ArrayShapeNode || $node instanceof ArrayTypeNode) {\n            return $checkArrays;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            $lower = strtolower($node->name);\n\n            if ($lower === 'mixed') {\n                return false;\n            }\n\n            if ($lower === 'callable') {\n                return Config::isInlineCallablesEnabled();\n            }\n\n            if (isset(self::ARRAY_TYPES[$lower])) {\n                return $checkArrays;\n            }\n\n            if (isset(self::SCALAR_TYPES[$lower])) {\n                return Config::isInlineScalarsEnabled();\n            }\n\n            return Config::isInlineObjectsEnabled();\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            $lower = strtolower($node->type->name);\n            if (isset(self::ARRAY_TYPES[$lower])) {\n                return $checkArrays;\n            }\n\n            if (Config::isInlineGenericsEnabled()) {\n                return true;\n            }\n\n            return Config::isInlineObjectsEnabled();\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return self::shouldValidateType($node->type);\n        }\n\n        if ($node instanceof UnionTypeNode || $node instanceof IntersectionTypeNode) {\n            foreach ($node->types as $t) {\n                if (self::shouldValidateType($t)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        return Config::isInlineScalarsEnabled();\n    }\n}\n","/typephp/src/Internal/Checker/ParamChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Docblock\\DocblockExtractor;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\HierarchyResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\StubManager;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @phpstan-import-type FunctionContract from DocblockParser\n *\n * @internal Evaluates function and method parameter contract validations (including dynamic @method calls via __call / __callStatic).\n */\nfinal class ParamChecker\n{\n    /**\n     * O(1) lookup table for iterable collection container types.\n     */\n    private const ITERABLE_TYPES = [\n        'array' => true,\n        'list' => true,\n        'iterable' => true,\n        'traversable' => true,\n    ];\n\n    /**\n     * O(1) lookup table for all collection and slice container types.\n     */\n    private const COLLECTION_TYPES = [\n        'array' => true,\n        'list' => true,\n        'iterable' => true,\n        'traversable' => true,\n        'non-empty-array' => true,\n        'non-empty-list' => true,\n    ];\n\n    /**\n     * 2D Cache for effective functions: [$function][$actualClassName] => effectiveFunction.\n     *\n     * @var array<string, array<string, string>>\n     */\n    private static array $effectiveFunctionCache = [];\n\n    /**\n     * O(1) Fast-path cache for methods determined to have no parameter contracts.\n     *\n     * @var array<string, true>\n     */\n    public static array $noParamContractCache = [];\n\n    /**\n     * 2D Cache for resolved parameter base types: [$effectiveFunction][$paramName] => TypeNode.\n     *\n     * @var array<string, array<string, TypeNode>>\n     */\n    private static array $baseTypeCache = [];\n\n    /**\n     * Cache for declared class template names by class FQCN.\n     *\n     * @var array<string, list<string>>\n     */\n    private static array $classDeclaredTemplateNamesCache = [];\n\n    /**\n     * Resets internal caches. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$effectiveFunctionCache = [];\n        self::$noParamContractCache = [];\n        self::$classDeclaredTemplateNamesCache = [];\n        ClassNameValidator::reset();\n        self::$baseTypeCache = [];\n    }\n\n    /**\n     * Checks if all parameters of a function are unconstrained (mixed or array).\n     * Uses the pre-computed flag from DocblockParser contract when available.\n     */\n    public static function areAllParamsUnconstrained(string $effectiveFunction): bool\n    {\n        if (str_contains($effectiveFunction, '__call')) {\n            return false;\n        }\n\n        $contract = DocblockParser::parse($effectiveFunction);\n\n        return $contract['allParamsUnconstrained'] ?? false;\n    }\n\n    /**\n     * Checks if a TypeNode represents an unconstrained type (mixed or array).\n     */\n    private static function isUnconstrained(TypeNode $typeNode): bool\n    {\n        if (! ($typeNode instanceof IdentifierTypeNode)) {\n            return false;\n        }\n        $lower = strtolower($typeNode->name);\n\n        return $lower === 'mixed' || $lower === 'array';\n    }\n\n    /**\n     * @param array<string, mixed> $vars\n     * @param FunctionContract|null $contract Pre-resolved contract to avoid re-parsing\n     */\n    public static function checkParams(\n        string $function,\n        array $vars,\n        object|string|null $thisOrClass,\n        TypeValidatorRegistry $registry,\n        string $effectiveFunction = '',\n        ?array $contract = null\n    ): ?ErrorMessage {\n        if (! Config::isParamsEnabled()) {\n            return null;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($effectiveFunction === '') {\n            $effectiveFunction = self::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n        }\n\n        $isMagicCall = str_ends_with($effectiveFunction, '::__call') || str_ends_with($effectiveFunction, '::__callStatic');\n\n        if (! $isMagicCall && isset(self::$noParamContractCache[$effectiveFunction])) {\n            return null;\n        }\n\n        if ($vars === [] && ! $isMagicCall) {\n            return null;\n        }\n\n        $magicError = self::handleMagicCall($effectiveFunction, $vars, $thisObj, $registry);\n        if ($magicError !== null) {\n            return $magicError;\n        }\n        if ($isMagicCall) {\n            return null;\n        }\n\n        $contract ??= DocblockParser::parse($effectiveFunction);\n\n        if (! $contract['hasParamContract']) {\n            self::$noParamContractCache[$effectiveFunction] = true;\n            self::$noParamContractCache[$function] = true;\n\n            return null;\n        }\n\n        $paramsUseGenerics = (bool) ($contract['paramsUseGenerics'] ?? true);\n        $methodTemplates = $contract['templates'];\n        $classTemplates = $contract['classTemplates'] ?? [];\n        $aliases = $contract['aliases'];\n        $hasMethodTemplates = (\\count($methodTemplates) > 0);\n        $sensitiveParams = $contract['sensitiveParams'] ?? [];\n\n        if (! $paramsUseGenerics && ! $hasMethodTemplates && \\count($aliases) === 0) {\n            return self::validateSimpleParams($contract['types'], $vars, $effectiveFunction, $registry, $sensitiveParams);\n        }\n\n        self::prepareGenericBindings($effectiveFunction, $methodTemplates, $thisObj, $classTemplates, $thisOrClass);\n\n        /** @var array<string, TemplateTagValueNode> $allTemplates */\n        $allTemplates = [...$classTemplates, ...$methodTemplates];\n\n        if (\\count($allTemplates) > 0 && $paramsUseGenerics) {\n            self::preInferGenericTemplates($contract['types'], $vars, $effectiveFunction, $thisObj, $allTemplates, $classTemplates);\n        }\n\n        $boundTemplates = (\\count($allTemplates) > 0)\n            ? TemplateManager::getBoundTemplates($effectiveFunction, $thisOrClass, $allTemplates)\n            : [];\n        $declaredTemplates = $allTemplates;\n\n        $baseTypes = self::resolveBaseTypes($contract['types'], $effectiveFunction, $thisObj, $aliases);\n\n        return self::validateAllParameters(\n            $contract['types'],\n            $baseTypes,\n            $vars,\n            $effectiveFunction,\n            $thisObj,\n            $allTemplates,\n            $aliases,\n            $boundTemplates,\n            $declaredTemplates,\n            $registry,\n            $classTemplates,\n            $thisOrClass,\n            $sensitiveParams\n        );\n    }\n\n    /**\n     * Validates simple parameters when no generics/aliases are involved.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, mixed> $vars\n     * @param array<string, bool> $sensitiveParams\n     */\n    private static function validateSimpleParams(\n        array $types,\n        array $vars,\n        string $effectiveFunction,\n        TypeValidatorRegistry $registry,\n        array $sensitiveParams = []\n    ): ?ErrorMessage {\n        foreach ($types as $paramName => $typeNode) {\n            if (isset($vars[$paramName]) || \\array_key_exists($paramName, $vars)) {\n                if (\n                    $typeNode instanceof ConditionalTypeForParameterNode ||\n                    $typeNode instanceof ConditionalTypeNode\n                ) {\n                    $typeNode = ConditionalChecker::resolve($typeNode, $vars, [], $registry, $effectiveFunction);\n                }\n\n                if (self::isUnconstrained($typeNode)) {\n                    continue;\n                }\n\n                $isSensitive = $sensitiveParams[$paramName] ?? false;\n                $err = $registry->validate($vars[$paramName], $typeNode, '', $isSensitive);\n                if ($err !== null) {\n                    return ErrorFactory::createError($effectiveFunction . '(): Argument $' . $paramName . $err->getMessage());\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Prepares generic bindings: clears call bindings and resolves inherited templates.\n     *\n     * @param array<string, TemplateTagValueNode> $methodTemplates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function prepareGenericBindings(\n        string $effectiveFunction,\n        array $methodTemplates,\n        ?object $thisObj,\n        array $classTemplates,\n        object|string|null $thisOrClass = null\n    ): void {\n        if (\\count($methodTemplates) > 0) {\n            TemplateManager::clearCallBindings($effectiveFunction, $methodTemplates);\n        }\n\n        if (\\count($classTemplates) > 0 && str_contains($effectiveFunction, '::')) {\n            $declaringClass = explode('::', $effectiveFunction, 2)[0];\n            if ($thisObj !== null && ! TemplateManager::hasInstanceBindings($thisObj)) {\n                TemplateManager::resolveInheritedTemplates($thisObj, $declaringClass);\n            } elseif ($thisObj === null) {\n                $targetClass = \\is_string($thisOrClass) && $thisOrClass !== '' ? $thisOrClass : $declaringClass;\n                TemplateManager::getClassInheritedBindings($targetClass);\n            }\n        }\n    }\n\n    /**\n     * Pre‑resolves and caches base types for each parameter using zero-allocation 2D lookup.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, TypeNode> $aliases\n     *\n     * @return array<string, TypeNode>\n     */\n    private static function resolveBaseTypes(\n        array $types,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $aliases\n    ): array {\n        $baseTypes = [];\n        foreach ($types as $paramName => $typeNode) {\n            if (! isset(self::$baseTypeCache[$effectiveFunction][$paramName])) {\n                if ($typeNode instanceof IdentifierTypeNode && isset($aliases[$typeNode->name])) {\n                    $typeNode = $aliases[$typeNode->name];\n                }\n                $resolved = SpecialTypeResolver::resolve($typeNode, $effectiveFunction, $thisObj);\n                self::$baseTypeCache[$effectiveFunction][$paramName] = $resolved;\n            }\n            $baseTypes[$paramName] = self::$baseTypeCache[$effectiveFunction][$paramName];\n        }\n\n        return $baseTypes;\n    }\n\n    /**\n     * Validates all parameters against their resolved base types.\n     *\n     * @param array<string, TypeNode> $contractTypes\n     * @param array<string, TypeNode> $baseTypes\n     * @param array<string, mixed> $vars\n     * @param array<string, TemplateTagValueNode> $allTemplates\n     * @param array<string, TypeNode> $aliases\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     * @param array<string, bool> $sensitiveParams\n     */\n    private static function validateAllParameters(\n        array $contractTypes,\n        array $baseTypes,\n        array $vars,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $allTemplates,\n        array $aliases,\n        array $boundTemplates,\n        array $declaredTemplates,\n        TypeValidatorRegistry $registry,\n        array $classTemplates,\n        object|string|null $thisOrClass = null,\n        array $sensitiveParams = []\n    ): ?ErrorMessage {\n        foreach ($contractTypes as $paramName => $_) {\n            if (! isset($vars[$paramName]) && ! \\array_key_exists($paramName, $vars)) {\n                continue;\n            }\n\n            $currentBoundTemplates = (\\count($allTemplates) > 0)\n                ? TemplateManager::getBoundTemplates($effectiveFunction, $thisOrClass, $allTemplates)\n                : $boundTemplates;\n\n            $isSensitive = $sensitiveParams[$paramName] ?? false;\n\n            $err = self::validateSingleParam(\n                $paramName,\n                $baseTypes[$paramName],\n                $vars[$paramName],\n                $effectiveFunction,\n                $thisObj,\n                $allTemplates,\n                $aliases,\n                $currentBoundTemplates,\n                $declaredTemplates,\n                $registry,\n                $classTemplates,\n                $vars,\n                $thisOrClass,\n                $isSensitive\n            );\n\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Resolves the actual runtime class name vs trait name with O(1) 2D memoization.\n     */\n    public static function resolveEffectiveFunction(string $function, object|string|null $thisOrClass, ?object $thisObj = null): string\n    {\n        if (! str_contains($function, '::')) {\n            return $function;\n        }\n\n        $actualClassName = \\is_object($thisOrClass) ? $thisOrClass::class : (\\is_string($thisOrClass) ? $thisOrClass : '');\n\n        if ($actualClassName === '') {\n            return $function;\n        }\n\n        if (str_starts_with($function, $actualClassName . '::') && HierarchyResolver::getTraitAliases($actualClassName) === []) {\n            return $function;\n        }\n\n        if (isset(self::$effectiveFunctionCache[$function][$actualClassName])) {\n            return self::$effectiveFunctionCache[$function][$actualClassName];\n        }\n\n        [$classOrTrait, $methodName] = explode('::', $function, 2);\n\n        $effectiveFunction = ($actualClassName !== $classOrTrait)\n            ? $actualClassName . '::' . $methodName\n            : $function;\n\n        if ($thisObj !== null) {\n            $traitAliases = HierarchyResolver::getTraitAliases($actualClassName);\n\n            if (\\count($traitAliases) > 0) {\n                $isTargetOfAlias = false;\n                foreach ($traitAliases as $originalTarget) {\n                    if (str_ends_with($originalTarget, '::' . $methodName)) {\n                        $isTargetOfAlias = true;\n\n                        break;\n                    }\n                }\n\n                if ($isTargetOfAlias) {\n                    $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 6);\n                    foreach ($trace as $frame) {\n                        $frameFunc = $frame['function'];\n                        $frameClass = $frame['class'] ?? '';\n                        if (($frameClass === $actualClassName || $frameClass === $classOrTrait) && isset($traitAliases[$frameFunc])) {\n                            return self::$effectiveFunctionCache[$function][$actualClassName] = $actualClassName . '::' . $frameFunc;\n                        }\n                    }\n                }\n            }\n        }\n\n        return self::$effectiveFunctionCache[$function][$actualClassName] = $effectiveFunction;\n    }\n\n    /**\n     * Intercepts and delegates dynamic @method calls routed via __call and __callStatic.\n     *\n     * @param array<string, mixed> $vars\n     */\n    private static function handleMagicCall(\n        string $effectiveFunction,\n        array $vars,\n        ?object $thisObj,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        if (! Config::isMagicMethodsEnabled()) {\n            return null;\n        }\n\n        if (! str_ends_with($effectiveFunction, '::__call') && ! str_ends_with($effectiveFunction, '::__callStatic')) {\n            return null;\n        }\n\n        $magicMethodName = array_values($vars)[0] ?? null;\n        $magicArgs = array_values($vars)[1] ?? [];\n\n        if (! \\is_string($magicMethodName) || ! \\is_array($magicArgs)) {\n            return null;\n        }\n\n        $className = explode('::', $effectiveFunction, 2)[0];\n        $magicContract = DocblockParser::parseMagicMethod($className, $magicMethodName);\n\n        if ($magicContract === null) {\n            return null;\n        }\n\n        $magicFunction = $className . '::' . $magicMethodName;\n\n        return self::validateMagicArguments($magicContract, $magicArgs, $magicFunction, $thisObj, $registry);\n    }\n\n    /**\n     * Pre-infers generic template parameters from closure typehints, array arguments, and generic object arguments.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, mixed> $vars\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function preInferGenericTemplates(\n        array $types,\n        array $vars,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates,\n        array $classTemplates = []\n    ): void {\n        $hasClosure = false;\n        foreach ($vars as $v) {\n            if ($v instanceof \\Closure) {\n                $hasClosure = true;\n\n                break;\n            }\n        }\n\n        if ($hasClosure) {\n            self::inferTemplatesFromClosures($types, $vars, $effectiveFunction, $thisObj, $templates, $classTemplates);\n        }\n\n        if (\\count($types) > 0) {\n            self::inferTemplatesFromArrays($types, $vars, $effectiveFunction, $thisObj, $templates);\n            self::inferTemplatesFromGenericObjects($types, $vars, $effectiveFunction, $thisObj, $templates, $classTemplates);\n        }\n    }\n\n    /**\n     * Infers generic template parameters from closure parameter typehints.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, mixed> $vars\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function inferTemplatesFromClosures(\n        array $types,\n        array $vars,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates,\n        array $classTemplates = []\n    ): void {\n        $callableNodes = self::extractCallableNodes($types);\n        if (\\count($callableNodes) === 0) {\n            return;\n        }\n\n        foreach ($callableNodes as $cParamName => $cTypeNode) {\n            if (! isset($vars[$cParamName]) || ! ($vars[$cParamName] instanceof \\Closure)) {\n                continue;\n            }\n\n            try {\n                $refClosure = new \\ReflectionFunction($vars[$cParamName]);\n                $closureParams = $refClosure->getParameters();\n\n                foreach ($cTypeNode->parameters as $idx => $pNode) {\n                    if ($pNode->type instanceof IdentifierTypeNode && isset($templates[$pNode->type->name]) && isset($closureParams[$idx])) {\n                        $tName = $pNode->type->name;\n                        $isClassLevel = ! TemplateManager::isMethodTemplate($effectiveFunction, $tName) && isset($classTemplates[$tName]);\n                        $targetObj = $isClassLevel ? $thisObj : null;\n\n                        $inferredCandidate = self::extractTypeFromClosureParameter($closureParams[$idx]);\n\n                        if ($inferredCandidate !== null) {\n                            $templateTag = $templates[$tName];\n                            $satisfiesBound = true;\n\n                            if ($templateTag->bound !== null) {\n                                $resolvedBound = SpecialTypeResolver::resolve($templateTag->bound, $effectiveFunction, $thisObj);\n                                $satisfiesBound = TemplateManager::checkVariance($inferredCandidate, $resolvedBound, GenericTypeNode::VARIANCE_COVARIANT);\n                            }\n\n                            if ($satisfiesBound) {\n                                TemplateManager::bindTemplate($effectiveFunction, $targetObj, $tName, $inferredCandidate);\n                            }\n                        }\n                    }\n                }\n            } catch (\\Throwable $e) {\n                // Silently ignore reflection errors\n            }\n        }\n    }\n\n    /**\n     * @param array<string, TypeNode> $types\n     *\n     * @return array<string, CallableTypeNode>\n     */\n    private static function extractCallableNodes(array $types): array\n    {\n        $callableNodes = [];\n        foreach ($types as $paramName => $tNode) {\n            if ($tNode instanceof CallableTypeNode) {\n                $callableNodes[$paramName] = $tNode;\n            } elseif ($tNode instanceof UnionTypeNode) {\n                foreach ($tNode->types as $subT) {\n                    if ($subT instanceof CallableTypeNode) {\n                        $callableNodes[$paramName] = $subT;\n\n                        break;\n                    }\n                }\n            }\n        }\n\n        return $callableNodes;\n    }\n\n    /**\n     * Extracts an inferred TypeNode from a closure parameter, ignoring `mixed`.\n     */\n    private static function extractTypeFromClosureParameter(\\ReflectionParameter $closureParam): ?TypeNode\n    {\n        if (! $closureParam->hasType()) {\n            return null;\n        }\n\n        $cType = $closureParam->getType();\n        if ($cType instanceof \\ReflectionNamedType) {\n            $cTypeName = $cType->getName();\n            if ($cTypeName !== 'mixed' && (class_exists($cTypeName) || interface_exists($cTypeName) || SpecialTypeResolver::isBuiltInTypeKeyword($cTypeName))) {\n                return new IdentifierTypeNode($cTypeName);\n            }\n        } elseif ($cType instanceof \\ReflectionUnionType) {\n            $unionSubTypes = [];\n            foreach ($cType->getTypes() as $subNamedType) {\n                if ($subNamedType instanceof \\ReflectionNamedType) {\n                    $subName = $subNamedType->getName();\n                    if ($subName !== 'mixed' && (class_exists($subName) || interface_exists($subName) || SpecialTypeResolver::isBuiltInTypeKeyword($subName))) {\n                        $unionSubTypes[] = new IdentifierTypeNode($subName);\n                    }\n                }\n            }\n            if (\\count($unionSubTypes) > 0) {\n                return \\count($unionSubTypes) === 1 ? $unionSubTypes[0] : new UnionTypeNode($unionSubTypes);\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Infers generic template parameters from array arguments.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, mixed> $vars\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function inferTemplatesFromArrays(\n        array $types,\n        array $vars,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates\n    ): void {\n        foreach ($types as $paramName => $typeNode) {\n            if (! isset($vars[$paramName]) || ! \\is_array($vars[$paramName]) || \\count($vars[$paramName]) === 0) {\n                continue;\n            }\n\n            self::inferArrayTemplatesFromAllElements($typeNode, $vars[$paramName], $effectiveFunction, $thisObj, $templates);\n        }\n    }\n\n    /**\n     * Extracts and unifies template parameters across all elements of an array argument.\n     * Uses Beartype O(1) hybrid random sampling on arrays > 128 items when hybrid mode is active.\n     *\n     * @param array<mixed> $arrVal\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function inferArrayTemplatesFromAllElements(\n        TypeNode $typeNode,\n        array $arrVal,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates\n    ): void {\n        if ($typeNode instanceof NullableTypeNode) {\n            $typeNode = $typeNode->type;\n        }\n\n        if ($typeNode instanceof GenericTypeNode) {\n            $baseType = strtolower($typeNode->type->name);\n            if (! isset(self::ITERABLE_TYPES[$baseType])) {\n                return;\n            }\n\n            $sampleItems = self::getSampleArraySlice($arrVal);\n            $genericCount = \\count($typeNode->genericTypes);\n\n            if ($genericCount === 1 && $typeNode->genericTypes[0] instanceof IdentifierTypeNode) {\n                self::inferSingleTemplateFromArraySamples($typeNode->genericTypes[0]->name, $sampleItems, $effectiveFunction, $thisObj, $templates);\n            } elseif ($genericCount >= 2) {\n                $keyTName = $typeNode->genericTypes[0] instanceof IdentifierTypeNode ? $typeNode->genericTypes[0]->name : null;\n                $valTName = $typeNode->genericTypes[1] instanceof IdentifierTypeNode ? $typeNode->genericTypes[1]->name : null;\n\n                $inferredKeyType = null;\n                $inferredValType = null;\n\n                foreach ($sampleItems as $key => $item) {\n                    if ($keyTName !== null) {\n                        $keyType = TemplateManager::inferTypeFromValue($key);\n                        $inferredKeyType = ($inferredKeyType === null) ? $keyType : self::unifyTypes($inferredKeyType, $keyType);\n                    }\n                    if ($valTName !== null) {\n                        $valType = TemplateManager::inferTypeFromValue($item);\n                        $inferredValType = ($inferredValType === null) ? $valType : self::unifyTypes($inferredValType, $valType);\n                    }\n                }\n\n                if ($keyTName !== null && $inferredKeyType !== null) {\n                    self::bindTemplateIfUnbound($keyTName, $inferredKeyType, $effectiveFunction, $thisObj, $templates);\n                }\n                if ($valTName !== null && $inferredValType !== null) {\n                    self::bindTemplateIfUnbound($valTName, $inferredValType, $effectiveFunction, $thisObj, $templates);\n                }\n            }\n        }\n    }\n\n    /**\n     * @param array<mixed> $sampleItems\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function inferSingleTemplateFromArraySamples(\n        string $templateName,\n        array $sampleItems,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates\n    ): void {\n        $inferredType = null;\n        foreach ($sampleItems as $item) {\n            $itemType = TemplateManager::inferTypeFromValue($item);\n            $inferredType = ($inferredType === null) ? $itemType : self::unifyTypes($inferredType, $itemType);\n        }\n\n        if ($inferredType !== null) {\n            self::bindTemplateIfUnbound($templateName, $inferredType, $effectiveFunction, $thisObj, $templates);\n        }\n    }\n\n    /**\n     * Extracts items for template inference, using hybrid sampling for arrays > 128 items.\n     *\n     * @param array<mixed> $arrVal\n     *\n     * @return array<mixed>\n     */\n    private static function getSampleArraySlice(array $arrVal): array\n    {\n        $count = \\count($arrVal);\n        if ($count <= Config::HYBRID_SAMPLE_THRESHOLD || ! Config::isArrayValidationHybrid()) {\n            return $arrVal;\n        }\n\n        $keys = array_keys($arrVal);\n        $sampleKeys = [$keys[0], $keys[$count - 1]];\n        $samplesToTake = min(3, $count - 2);\n        for ($i = 0; $i < $samplesToTake; $i++) {\n            $sampleKeys[] = $keys[mt_rand(1, $count - 2)];\n        }\n\n        $samples = [];\n        foreach ($sampleKeys as $k) {\n            $samples[$k] = $arrVal[$k];\n        }\n\n        return $samples;\n    }\n\n    /**\n     * Binds a template parameter if it is not already bound in the current scope.\n     *\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function bindTemplateIfUnbound(\n        string $templateName,\n        TypeNode $inferredType,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates\n    ): void {\n        $contract = DocblockParser::parse($effectiveFunction);\n        $classTemplates = $contract['classTemplates'] ?? [];\n        $isClassLevelTemplate = ! TemplateManager::isMethodTemplate($effectiveFunction, $templateName) && isset($classTemplates[$templateName]);\n        $targetObj = $isClassLevelTemplate ? $thisObj : null;\n\n        if (isset($templates[$templateName]) && ! TemplateManager::isBound($effectiveFunction, $targetObj, $templateName)) {\n            TemplateManager::bindTemplate($effectiveFunction, $targetObj, $templateName, $inferredType);\n        }\n    }\n\n    /**\n     * Pre-infers generic template parameters from generic object arguments (e.g. PBox<T> or array<K, PBox<T>>).\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, mixed> $vars\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function inferTemplatesFromGenericObjects(\n        array $types,\n        array $vars,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates,\n        array $classTemplates = []\n    ): void {\n        foreach ($types as $paramName => $typeNode) {\n            if (! isset($vars[$paramName])) {\n                continue;\n            }\n\n            $value = $vars[$paramName];\n            self::inferGenericObjectNode($typeNode, $value, $effectiveFunction, $thisObj, $templates, $classTemplates);\n        }\n    }\n\n    /**\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function inferGenericObjectNode(\n        TypeNode $typeNode,\n        mixed $value,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates,\n        array $classTemplates = []\n    ): void {\n        if ($typeNode instanceof NullableTypeNode) {\n            $typeNode = $typeNode->type;\n        }\n\n        if ($typeNode instanceof GenericTypeNode && \\is_object($value)) {\n            $baseName = strtolower($typeNode->type->name);\n            if (isset(self::COLLECTION_TYPES[$baseName])) {\n                return;\n            }\n\n            $boundOnInstance = TemplateManager::getBoundTemplatesForInstance($value);\n            if ($boundOnInstance === []) {\n                return;\n            }\n\n            $targetClassFqcn = SpecialTypeResolver::resolveFqcn($typeNode->type->name, new \\ReflectionClass($value));\n            $targetTemplateNames = self::$classDeclaredTemplateNamesCache[$targetClassFqcn] ?? null;\n\n            if ($targetTemplateNames === null) {\n                $targetTemplateNames = [];\n                if (class_exists($targetClassFqcn, false) || class_exists($targetClassFqcn) || interface_exists($targetClassFqcn) || trait_exists($targetClassFqcn)) {\n                    try {\n                        $targetRef = new \\ReflectionClass($targetClassFqcn);\n                        $targetDoc = StubManager::getClassDoc($targetClassFqcn) ?? $targetRef->getDocComment();\n                        if ($targetDoc !== false && $targetDoc !== null) {\n                            $targetPhpDocNode = DocblockExtractor::parseDocString($targetDoc);\n                            $targetTemplateNames = array_keys(DocblockExtractor::extractTemplates($targetPhpDocNode));\n                        }\n                    } catch (\\Throwable $e) {\n                    }\n                }\n                self::$classDeclaredTemplateNamesCache[$targetClassFqcn] = $targetTemplateNames;\n            }\n\n            $instanceBoundTypes = array_values($boundOnInstance);\n\n            foreach ($typeNode->genericTypes as $idx => $gtNode) {\n                if ($gtNode instanceof IdentifierTypeNode && isset($templates[$gtNode->name])) {\n                    $tName = $gtNode->name;\n                    $isClassLevel = ! TemplateManager::isMethodTemplate($effectiveFunction, $tName) && isset($classTemplates[$tName]);\n                    $targetObj = $isClassLevel ? $thisObj : null;\n\n                    if (! TemplateManager::isBound($effectiveFunction, $targetObj, $tName)) {\n                        $targetTemplateName = $targetTemplateNames[$idx] ?? null;\n                        $inferredCandidate = null;\n\n                        if ($targetTemplateName !== null && isset($boundOnInstance[$targetTemplateName])) {\n                            $inferredCandidate = $boundOnInstance[$targetTemplateName];\n                        } elseif (isset($instanceBoundTypes[$idx])) {\n                            $inferredCandidate = $instanceBoundTypes[$idx];\n                        }\n\n                        if ($inferredCandidate !== null) {\n                            $templateTag = $templates[$tName];\n                            $satisfiesBound = true;\n\n                            if ($templateTag->bound !== null) {\n                                $resolvedBound = SpecialTypeResolver::resolve($templateTag->bound, $effectiveFunction, $thisObj);\n                                $satisfiesBound = TemplateManager::checkVariance($inferredCandidate, $resolvedBound, GenericTypeNode::VARIANCE_COVARIANT);\n                            }\n\n                            if ($satisfiesBound) {\n                                TemplateManager::bindTemplate($effectiveFunction, $targetObj, $tName, $inferredCandidate);\n                            }\n                        }\n                    }\n                }\n            }\n        } elseif (\\is_array($value)) {\n            $innerType = null;\n            if ($typeNode instanceof ArrayTypeNode) {\n                $innerType = $typeNode->type;\n            } elseif ($typeNode instanceof GenericTypeNode) {\n                $baseName = strtolower($typeNode->type->name);\n                if (isset(self::COLLECTION_TYPES[$baseName])) {\n                    $innerType = $typeNode->genericTypes[1] ?? $typeNode->genericTypes[0] ?? null;\n                }\n            }\n\n            if ($innerType !== null) {\n                foreach ($value as $item) {\n                    if (\\is_object($item)) {\n                        self::inferGenericObjectNode($innerType, $item, $effectiveFunction, $thisObj, $templates, $classTemplates);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Unified single-parameter validation pipeline.\n     *\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TypeNode> $aliases\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param TypeValidatorRegistry $registry\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     * @param array<int|string, mixed> $vars\n     */\n    private static function validateSingleParam(\n        string $paramName,\n        TypeNode $typeNode,\n        mixed $val,\n        string $effectiveFunction,\n        ?object $thisObj,\n        array $templates,\n        array $aliases,\n        array $boundTemplates,\n        array $declaredTemplates,\n        TypeValidatorRegistry $registry,\n        array $classTemplates = [],\n        array $vars = [],\n        object|string|null $thisOrClass = null,\n        bool $isSensitive = false\n    ): ?ErrorMessage {\n        if (\n            $typeNode instanceof ConditionalTypeForParameterNode ||\n            $typeNode instanceof ConditionalTypeNode\n        ) {\n            $typeNode = ConditionalChecker::resolve($typeNode, $vars, $boundTemplates, $registry, $effectiveFunction);\n        }\n\n        if (self::isUnconstrained($typeNode)) {\n            return null;\n        }\n\n        $isClassStringT = ($typeNode instanceof GenericTypeNode && self::isClassStringTemplate($typeNode, $templates));\n        $isBareTemplate = self::getTemplateName($typeNode, $templates) !== null;\n        $shouldSkipTemplateSub = $isBareTemplate || $isClassStringT;\n\n        if (! $shouldSkipTemplateSub && (\\count($boundTemplates) > 0 || \\count($declaredTemplates) > 0)) {\n            $typeNode = TemplateSubstitutor::substitute($typeNode, $boundTemplates, $declaredTemplates);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $effectiveFunction, $thisObj);\n        }\n\n        if (\n            $typeNode instanceof ConditionalTypeForParameterNode ||\n            $typeNode instanceof ConditionalTypeNode\n        ) {\n            $typeNode = ConditionalChecker::resolve($typeNode, $vars, $boundTemplates, $registry, $effectiveFunction);\n        }\n\n        if ($typeNode instanceof GenericTypeNode && self::isClassStringTemplate($typeNode, $templates)) {\n            return self::resolveClassStringTemplate($typeNode, $val, $paramName, $effectiveFunction, $thisObj, $templates, $classTemplates, $isSensitive);\n        }\n\n        if (self::getTemplateName($typeNode, $templates) !== null) {\n            return self::resolveTemplateParam($typeNode, $val, $paramName, $effectiveFunction, $thisObj, $templates, $registry, $classTemplates, $thisOrClass);\n        }\n\n        return $registry->validate($val, $typeNode, $effectiveFunction . '(): Argument $' . $paramName, $isSensitive);\n    }\n\n    /**\n     * @param array{return: ?TypeNode, parameters: array<int, array{name: string, type: ?TypeNode, isVariadic: bool, isOptional: bool}>, aliases: array<string, TypeNode>, templates: array<string, TemplateTagValueNode>} $magicContract\n     * @param array<int|string, mixed> $args\n     */\n    private static function validateMagicArguments(\n        array $magicContract,\n        array $args,\n        string $function,\n        ?object $thisObj,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        $templates = $magicContract['templates'];\n        $aliases = $magicContract['aliases'];\n        $parameters = $magicContract['parameters'];\n        $argValues = array_values($args);\n        $argKeys = array_keys($args);\n\n        $boundTemplates = TemplateManager::getBoundTemplates($function, $thisObj, $templates);\n        $declaredTemplates = $templates;\n\n        foreach ($parameters as $index => $p) {\n            $paramName = $p['name'];\n            $typeNode = $p['type'];\n            $isVariadic = $p['isVariadic'];\n\n            if ($typeNode === null) {\n                continue;\n            }\n\n            [$val, $hasVal] = self::extractMagicArgumentValue($paramName, $index, $isVariadic, $args, $argValues, $argKeys);\n            if (! $hasVal) {\n                continue;\n            }\n\n            if ($isVariadic) {\n                $typeNode = new ArrayTypeNode($typeNode);\n            }\n\n            $err = self::validateSingleParam(\n                $paramName,\n                $typeNode,\n                $val,\n                $function,\n                $thisObj,\n                $templates,\n                $aliases,\n                $boundTemplates,\n                $declaredTemplates,\n                $registry,\n                [],\n                $args\n            );\n\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array<int|string, mixed> $args\n     * @param array<int, mixed> $argValues\n     * @param array<int, int|string> $argKeys\n     *\n     * @return array{0: mixed, 1: bool}\n     */\n    private static function extractMagicArgumentValue(\n        string $paramName,\n        int $index,\n        bool $isVariadic,\n        array $args,\n        array $argValues,\n        array $argKeys\n    ): array {\n        if ($isVariadic) {\n            if (\\array_key_exists($paramName, $args)) {\n                return [[$args[$paramName]], true];\n            }\n\n            $val = [];\n            $hasVal = false;\n            $count = \\count($argValues);\n            for ($i = $index; $i < $count; $i++) {\n                if (\\is_int($argKeys[$i])) {\n                    $val[] = $argValues[$i];\n                    $hasVal = true;\n                }\n            }\n\n            return [$val, $hasVal];\n        }\n\n        if (\\array_key_exists($paramName, $args)) {\n            return [$args[$paramName], true];\n        }\n\n        if (\\array_key_exists($index, $argValues)) {\n            return [$argValues[$index], true];\n        }\n\n        return [null, false];\n    }\n\n    /**\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function isClassStringTemplate(GenericTypeNode $typeNode, array $templates): bool\n    {\n        return isset($typeNode->genericTypes[0])\n            && $typeNode->genericTypes[0] instanceof IdentifierTypeNode\n            && strtolower($typeNode->type->name) === 'class-string'\n            && isset($templates[$typeNode->genericTypes[0]->name]);\n    }\n\n    /**\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function resolveClassStringTemplate(\n        GenericTypeNode $typeNode,\n        mixed $val,\n        string $paramName,\n        string $function,\n        ?object $thisObj,\n        array $templates,\n        array $classTemplates = [],\n        bool $isSensitive = false\n    ): ?ErrorMessage {\n        /** @var IdentifierTypeNode $innerType */\n        $innerType = $typeNode->genericTypes[0];\n        $templateName = $innerType->name;\n        $templateNode = $templates[$templateName];\n        $isClassLevelTemplate = ! TemplateManager::isMethodTemplate($function, $templateName) && isset($classTemplates[$templateName]);\n        $targetObj = $isClassLevelTemplate ? $thisObj : null;\n\n        if (! TemplateManager::isBound($function, $targetObj, $templateName)) {\n            if (! \\is_string($val) || ! ClassNameValidator::isValidClassString($val)) {\n                return ErrorFactory::createError($function . '(): Argument $' . $paramName . ' must be a valid class-string, ' . TypeFormatter::formatGivenValue($val, $isSensitive) . ' given');\n            }\n\n            if ($templateNode->bound !== null) {\n                $boundLower = $templateNode->bound instanceof IdentifierTypeNode ? strtolower($templateNode->bound->name) : '';\n                if ($boundLower !== 'object' && $boundLower !== 'mixed') {\n                    $resolvedBound = SpecialTypeResolver::resolve($templateNode->bound, $function, $thisObj);\n                    if (! self::checkClassStringSatisfiesBound($val, $resolvedBound)) {\n                        $boundDisplay = (string) $resolvedBound;\n                        $displayVal = $isSensitive ? 'string given' : \"'\" . $val . \"' given\";\n\n                        return ErrorFactory::createError($function . '(): Argument $' . $paramName . ' (class-string<' . $templateName . '>) must be a class-string of ' . $boundDisplay . ', ' . $displayVal);\n                    }\n                }\n            }\n\n            $classNode = TemplateManager::$classNodeCache[$val] ??= new IdentifierTypeNode($val);\n            TemplateManager::bindTemplate($function, $targetObj, $templateName, $classNode);\n        } else {\n            $expectedTypeNode = TemplateManager::getBoundType($function, $targetObj, $templateName);\n            if ($expectedTypeNode !== null) {\n                if (! \\is_string($val) || ! self::checkClassStringSatisfiesBound($val, $expectedTypeNode)) {\n                    $valStr = TypeFormatter::formatGivenValue($val, $isSensitive);\n                    $targetDisplay = (string) $expectedTypeNode;\n\n                    return ErrorFactory::createError($function . '(): Argument $' . $paramName . ' must be a class-string of ' . $targetDisplay . ', ' . $valStr . ' given');\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private static function checkClassStringSatisfiesBound(string $val, TypeNode $boundNode): bool\n    {\n        if ($boundNode instanceof IdentifierTypeNode) {\n            $boundName = $boundNode->name;\n            $lowerBound = strtolower($boundName);\n            if ($lowerBound === 'object' || $lowerBound === 'mixed') {\n                return true;\n            }\n\n            return is_a($val, $boundName, allow_string: true);\n        }\n\n        if ($boundNode instanceof UnionTypeNode) {\n            foreach ($boundNode->types as $unionType) {\n                if (self::checkClassStringSatisfiesBound($val, $unionType)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($boundNode instanceof IntersectionTypeNode) {\n            foreach ($boundNode->types as $intersectionType) {\n                if (! self::checkClassStringSatisfiesBound($val, $intersectionType)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        return true;\n    }\n\n    /**\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    private static function getTemplateName(TypeNode $typeNode, array $templates): ?string\n    {\n        if ($typeNode instanceof IdentifierTypeNode && isset($templates[$typeNode->name])) {\n            return $typeNode->name;\n        }\n\n        if ($typeNode instanceof NullableTypeNode && $typeNode->type instanceof IdentifierTypeNode && isset($templates[$typeNode->type->name])) {\n            return $typeNode->type->name;\n        }\n\n        if ($typeNode instanceof ArrayTypeNode && $typeNode->type instanceof IdentifierTypeNode && isset($templates[$typeNode->type->name])) {\n            return $typeNode->type->name;\n        }\n\n        if ($typeNode instanceof UnionTypeNode && \\count($typeNode->types) === 2) {\n            $t0 = $typeNode->types[0];\n            $t1 = $typeNode->types[1];\n\n            if ($t0 instanceof IdentifierTypeNode && isset($templates[$t0->name]) && $t1 instanceof IdentifierTypeNode && strtolower($t1->name) === 'null') {\n                return $t0->name;\n            }\n            if ($t1 instanceof IdentifierTypeNode && isset($templates[$t1->name]) && $t0 instanceof IdentifierTypeNode && strtolower($t0->name) === 'null') {\n                return $t1->name;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     */\n    private static function resolveTemplateParam(\n        TypeNode $typeNode,\n        mixed $val,\n        string $paramName,\n        string $function,\n        ?object $thisObj,\n        array $templates,\n        TypeValidatorRegistry $registry,\n        array $classTemplates = [],\n        object|string|null $thisOrClass = null\n    ): ?ErrorMessage {\n        $templateName = self::getTemplateName($typeNode, $templates);\n        if ($templateName === null || ! isset($templates[$templateName])) {\n            return null;\n        }\n\n        $templateNode = $templates[$templateName];\n        $isVariadic = $typeNode instanceof ArrayTypeNode;\n        $isNullable = ($typeNode instanceof NullableTypeNode) || ($typeNode instanceof UnionTypeNode && self::typeContainsNull($typeNode));\n        $isClassLevelTemplate = ! TemplateManager::isMethodTemplate($function, $templateName) && isset($classTemplates[$templateName]);\n        $targetObjOrClass = $isClassLevelTemplate ? ($thisObj ?? $thisOrClass) : null;\n        $allowsNullInBound = ($templateNode->bound !== null && self::typeContainsNull($templateNode->bound));\n\n        if ($isNullable && $val === null) {\n            if ($allowsNullInBound && ! TemplateManager::isBound($function, $targetObjOrClass, $templateName)) {\n                TemplateManager::bindTemplate($function, $thisObj, $templateName, new IdentifierTypeNode('null'));\n            }\n\n            return null;\n        }\n\n        if (! TemplateManager::isBound($function, $targetObjOrClass, $templateName)) {\n            return self::bindInitialTemplate(\n                $val,\n                $paramName,\n                $function,\n                $thisObj,\n                $thisObj,\n                $templateName,\n                $templateNode,\n                $isVariadic,\n                $isClassLevelTemplate,\n                $registry\n            );\n        }\n\n        return self::validateBoundTemplate(\n            $val,\n            $paramName,\n            $function,\n            $thisObj,\n            $targetObjOrClass,\n            $templateName,\n            $templateNode,\n            $isVariadic,\n            $isClassLevelTemplate,\n            $registry\n        );\n    }\n\n    private static function bindInitialTemplate(\n        mixed $val,\n        string $paramName,\n        string $function,\n        ?object $thisObj,\n        ?object $targetObj,\n        string $templateName,\n        TemplateTagValueNode $templateNode,\n        bool $isVariadic,\n        bool $isClassLevelTemplate,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        $sampleVal = ($isVariadic && \\is_array($val)) ? ($val[0] ?? null) : $val;\n        $inferredType = TemplateManager::inferTypeFromValue($sampleVal);\n\n        if ($templateNode->bound !== null) {\n            $resolvedBound = SpecialTypeResolver::resolve($templateNode->bound, $function, $thisObj);\n            $err = $registry->validate($sampleVal, $resolvedBound, $function . '(): Argument $' . $paramName . ' (template ' . $templateName . ')');\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        TemplateManager::bindTemplate($function, $targetObj, $templateName, $inferredType);\n\n        if ($isVariadic && \\is_array($val)) {\n            return self::validateVariadicList(\n                $val,\n                $paramName,\n                $function,\n                $thisObj,\n                $targetObj,\n                $templateName,\n                $templateNode,\n                $inferredType,\n                $isClassLevelTemplate,\n                $registry\n            );\n        }\n\n        return null;\n    }\n\n    private static function validateBoundTemplate(\n        mixed $val,\n        string $paramName,\n        string $function,\n        ?object $thisObj,\n        object|string|null $targetObj,\n        string $templateName,\n        TemplateTagValueNode $templateNode,\n        bool $isVariadic,\n        bool $isClassLevelTemplate,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        $expectedTypeNode = TemplateManager::getBoundType($function, $targetObj, $templateName);\n        if ($expectedTypeNode === null) {\n            return null;\n        }\n\n        $targetObjOnly = \\is_object($targetObj) ? $targetObj : null;\n\n        if ($expectedTypeNode instanceof IdentifierTypeNode && $expectedTypeNode->name === $templateName) {\n            $inferredType = TemplateManager::inferTypeFromValue($val);\n            TemplateManager::bindTemplate($function, $targetObjOnly, $templateName, $inferredType);\n\n            return null;\n        }\n\n        if ($isVariadic && \\is_array($val)) {\n            return self::validateVariadicList(\n                $val,\n                $paramName,\n                $function,\n                $thisObj,\n                $targetObjOnly,\n                $templateName,\n                $templateNode,\n                $expectedTypeNode,\n                $isClassLevelTemplate,\n                $registry\n            );\n        }\n\n        $context = $function . '(): Argument $' . $paramName;\n        $err = $registry->validate($val, $expectedTypeNode, $context . ' (template ' . $templateName . ' = ' . $expectedTypeNode . ')');\n\n        if ($err !== null) {\n            return self::tryWidenTemplate(\n                $val,\n                $expectedTypeNode,\n                $templateNode,\n                $isClassLevelTemplate,\n                $function,\n                $thisObj,\n                $targetObjOnly,\n                $templateName,\n                $context,\n                $err,\n                $registry\n            );\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array<mixed> $items\n     */\n    private static function validateVariadicList(\n        array $items,\n        string $paramName,\n        string $function,\n        ?object $thisObj,\n        ?object $targetObj,\n        string $templateName,\n        TemplateTagValueNode $templateNode,\n        TypeNode &$currentType,\n        bool $isClassLevelTemplate,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        foreach ($items as $idx => $item) {\n            $context = $function . '(): Argument $' . $paramName . '[' . $idx . ']';\n            $err = $registry->validate($item, $currentType, $context . ' (template ' . $templateName . ' = ' . $currentType . ')');\n\n            if ($err !== null) {\n                $widenErr = self::tryWidenTemplate(\n                    $item,\n                    $currentType,\n                    $templateNode,\n                    $isClassLevelTemplate,\n                    $function,\n                    $thisObj,\n                    $targetObj,\n                    $templateName,\n                    $context,\n                    $err,\n                    $registry\n                );\n                if ($widenErr !== null) {\n                    return $widenErr;\n                }\n                $currentType = TemplateManager::getBoundType($function, $targetObj, $templateName) ?? $currentType;\n            }\n        }\n\n        return null;\n    }\n\n    private static function tryWidenTemplate(\n        mixed $val,\n        TypeNode $currentType,\n        TemplateTagValueNode $templateNode,\n        bool $isClassLevelTemplate,\n        string $function,\n        ?object $thisObj,\n        ?object $targetObj,\n        string $templateName,\n        string $context,\n        ErrorMessage $originalError,\n        TypeValidatorRegistry $registry\n    ): ?ErrorMessage {\n        if ($isClassLevelTemplate || $templateNode->bound === null) {\n            return $originalError;\n        }\n\n        $resolvedBound = SpecialTypeResolver::resolve($templateNode->bound, $function, $thisObj);\n\n        $boundErr = $registry->validate($val, $resolvedBound, $context . ' (template ' . $templateName . ')');\n\n        if ($boundErr === null) {\n            $newInferred = TemplateManager::inferTypeFromValue($val);\n            $unifiedType = self::unifyTypes($currentType, $newInferred);\n            TemplateManager::bindTemplate($function, $targetObj, $templateName, $unifiedType);\n\n            return null;\n        }\n\n        return $originalError;\n    }\n\n    /**\n     * Unifies two types into a combined UnionTypeNode, deduplicating identical member types.\n     */\n    private static function unifyTypes(TypeNode $type1, TypeNode $type2): TypeNode\n    {\n        if ((string) $type1 === (string) $type2) {\n            return $type1;\n        }\n\n        $types = [];\n        if ($type1 instanceof UnionTypeNode) {\n            $types = $type1->types;\n        } else {\n            $types[] = $type1;\n        }\n\n        if ($type2 instanceof UnionTypeNode) {\n            foreach ($type2->types as $t) {\n                $types[] = $t;\n            }\n        } else {\n            $types[] = $type2;\n        }\n\n        $unique = [];\n        $deduped = [];\n        foreach ($types as $t) {\n            $str = (string) $t;\n            if (! isset($unique[$str])) {\n                $unique[$str] = true;\n                $deduped[] = $t;\n            }\n        }\n\n        return \\count($deduped) === 1 ? $deduped[0] : new UnionTypeNode($deduped);\n    }\n\n    private static function typeContainsNull(TypeNode $node): bool\n    {\n        if ($node instanceof NullableTypeNode) {\n            return true;\n        }\n\n        if ($node instanceof IdentifierTypeNode && strtolower($node->name) === 'null') {\n            return true;\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            foreach ($node->types as $t) {\n                if (self::typeContainsNull($t)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n}\n","/typephp/src/Internal/Checker/ParamOutChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @internal Evaluates by-reference parameter post-conditions (@param-out, @phpstan-param-out, @psalm-param-out).\n */\nfinal class ParamOutChecker\n{\n    /**\n     * O(1) Fast-path cache for methods determined to have no param-out contracts.\n     *\n     * @var array<string, true>\n     */\n    public static array $noParamOutContractCache = [];\n\n    public static function reset(): void\n    {\n        self::$noParamOutContractCache = [];\n    }\n\n    public static function checkParamOut(\n        string $function,\n        string $paramName,\n        mixed $value,\n        object|string|null $thisOrClass,\n        TypeValidatorRegistry $registry,\n        string $effectiveFunction = ''\n    ): ?ErrorMessage {\n        if (! Config::isParamsEnabled()) {\n            return null;\n        }\n\n        if (isset(self::$noParamOutContractCache[$function])) {\n            return null;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($effectiveFunction === '') {\n            $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n        }\n\n        if (isset(self::$noParamOutContractCache[$effectiveFunction])) {\n            self::$noParamOutContractCache[$function] = true;\n\n            return null;\n        }\n\n        $contract = DocblockParser::parse($effectiveFunction);\n\n        if (! ($contract['hasParamOutContract'] ?? false)) {\n            self::$noParamOutContractCache[$effectiveFunction] = true;\n            self::$noParamOutContractCache[$function] = true;\n\n            return null;\n        }\n\n        $paramOuts = $contract['paramOuts'] ?? [];\n\n        if (! isset($paramOuts[$paramName])) {\n            return null;\n        }\n\n        $typeNode = $paramOuts[$paramName];\n        $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n        $boundTemplates = (\\count($allTemplates) > 0)\n            ? TemplateManager::getBoundTemplates($effectiveFunction, $thisObj, $allTemplates)\n            : [];\n\n        if (\\count($boundTemplates) > 0 || \\count($allTemplates) > 0) {\n            $typeNode = TemplateSubstitutor::substitute($typeNode, $boundTemplates, $allTemplates);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $effectiveFunction, $thisObj);\n        }\n\n        $context = $effectiveFunction . '(): Argument &$' . $paramName . ' (param-out)';\n\n        $err = $registry->validate($value, $typeNode, $context);\n        if ($err !== null) {\n            return $err;\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Checker/ReturnChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse Traversable;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\nuse TypePHP\\Internal\\Wrapper\\CallableWrapper;\n\n/**\n * @phpstan-import-type FunctionContract from DocblockParser\n *\n * @internal Evaluates function and method return contract validations (including dynamic @method calls via __call / __callStatic).\n */\nfinal class ReturnChecker\n{\n    /**\n     * Fast O(1) lookup set for generic iterable return types.\n     */\n    private const GENERIC_ITERABLES = [\n        'iterable' => true,\n        'traversable' => true,\n        'iterator' => true,\n        'generator' => true,\n    ];\n\n    /**\n     * O(1) Fast-path cache for methods determined to have no return contracts.\n     *\n     * @var array<string, true>\n     */\n    public static array $noReturnContractCache = [];\n\n    /**\n     * In-memory cache for unbound generic return types.\n     *\n     * @var array<string, TypeNode>\n     */\n    public static array $unboundReturnCache = [];\n\n    /**\n     * Memoized static return type resolutions for non-dynamic, non-generic methods.\n     *\n     * @var array<string, TypeNode>\n     */\n    private static array $resolvedStaticReturnCache = [];\n\n    /**\n     * In-memory 2D cache for concrete substituted generic return types: [$function][$templateSignature] => TypeNode.\n     *\n     * @var array<string, array<string, TypeNode>>\n     */\n    public static array $substitutedReturnCache = [];\n\n    /**\n     * Resets internal caches. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$noReturnContractCache = [];\n        self::$resolvedStaticReturnCache = [];\n        self::$unboundReturnCache = [];\n        self::$substitutedReturnCache = [];\n    }\n\n    /**\n     * Checks if the return type of a function is unconstrained (mixed or array).\n     * Uses the pre-computed flag from DocblockParser contract when available.\n     */\n    public static function isReturnUnconstrained(string $effectiveFunction): bool\n    {\n        if (str_contains($effectiveFunction, '__call')) {\n            return false;\n        }\n\n        $contract = DocblockParser::parse($effectiveFunction);\n\n        return $contract['returnUnconstrained'] ?? false;\n    }\n\n    /**\n     * @param array<string, mixed> $vars\n     * @param FunctionContract|null $contract Pre-resolved contract to avoid re-parsing\n     */\n    public static function checkReturn(\n        string $function,\n        mixed $value,\n        object|string|null $thisOrClass,\n        array $vars,\n        TypeValidatorRegistry $registry,\n        callable $wrapIterableCallback,\n        string $effectiveFunction = '',\n        ?array $contract = null\n    ): mixed {\n        if (! Config::isReturnsEnabled()) {\n            return $value;\n        }\n\n        if (isset(self::$noReturnContractCache[$function])) {\n            return $value;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($effectiveFunction === '') {\n            $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n        }\n\n        if (isset(self::$noReturnContractCache[$effectiveFunction])) {\n            self::$noReturnContractCache[$function] = true;\n\n            return $value;\n        }\n\n        $isMagicCall = str_contains($effectiveFunction, '__call');\n        $magicResult = self::handleMagicReturn(\n            $effectiveFunction,\n            $value,\n            $thisObj,\n            $vars,\n            $registry,\n            $wrapIterableCallback\n        );\n        if ($magicResult !== null) {\n            return $magicResult;\n        }\n        if ($isMagicCall) {\n            return $value;\n        }\n\n        $contract ??= DocblockParser::parse($effectiveFunction);\n\n        if (! ($contract['hasReturnContract'] ?? ($contract['return'] !== null))) {\n            self::$noReturnContractCache[$effectiveFunction] = true;\n            self::$noReturnContractCache[$function] = true;\n\n            return $value;\n        }\n\n        $returnTypeNode = $contract['return'];\n        if ($returnTypeNode === null) {\n            self::$noReturnContractCache[$effectiveFunction] = true;\n            self::$noReturnContractCache[$function] = true;\n\n            return $value;\n        }\n\n        $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n\n        return self::evaluateReturn(\n            $returnTypeNode,\n            $value,\n            $effectiveFunction,\n            $thisObj,\n            $vars,\n            $contract['aliases'] ?? [],\n            $allTemplates,\n            $registry,\n            $wrapIterableCallback,\n            $contract\n        );\n    }\n\n    /**\n     * Intercepts and evaluates return contracts for dynamic @method calls routed via __call and __callStatic.\n     *\n     * @param array<string, mixed> $vars\n     */\n    private static function handleMagicReturn(\n        string $effectiveFunction,\n        mixed $value,\n        ?object $thisObj,\n        array $vars,\n        TypeValidatorRegistry $registry,\n        callable $wrapIterableCallback\n    ): mixed {\n        if (! Config::isMagicMethodsEnabled()) {\n            return null;\n        }\n\n        if (! str_ends_with($effectiveFunction, '::__call') && ! str_ends_with($effectiveFunction, '::__callStatic')) {\n            return null;\n        }\n\n        $magicMethodName = array_values($vars)[0] ?? null;\n        $rawMagicArgs = array_values($vars)[1] ?? [];\n        /** @var array<int|string, mixed> $magicArgs */\n        $magicArgs = \\is_array($rawMagicArgs) ? $rawMagicArgs : [];\n\n        if (! \\is_string($magicMethodName)) {\n            return null;\n        }\n\n        $className = explode('::', $effectiveFunction, 2)[0];\n        $magicContract = DocblockParser::parseMagicMethod($className, $magicMethodName);\n        if ($magicContract === null || $magicContract['return'] === null) {\n            return null;\n        }\n\n        $magicFunction = $className . '::' . $magicMethodName;\n\n        return self::evaluateReturn(\n            $magicContract['return'],\n            $value,\n            $magicFunction,\n            $thisObj,\n            $magicArgs,\n            $magicContract['aliases'] ?? [],\n            $magicContract['templates'] ?? [],\n            $registry,\n            $wrapIterableCallback\n        );\n    }\n\n    /**\n     * Unified return value validation pipeline.\n     *\n     * @param array<int|string, mixed> $vars\n     * @param array<string, TypeNode> $aliases\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param FunctionContract|array{} $contract\n     */\n    private static function evaluateReturn(\n        TypeNode $returnTypeNode,\n        mixed $value,\n        string $function,\n        ?object $thisObj,\n        array $vars,\n        array $aliases,\n        array $templates,\n        TypeValidatorRegistry $registry,\n        callable $wrapIterableCallback,\n        array $contract = []\n    ): mixed {\n        if ($contract['returnIsThis'] ?? false) {\n            $err = SpecialTypeResolver::checkThisIdentity($returnTypeNode, $value, $thisObj, $function);\n            if ($err !== null) {\n                return $err;\n            }\n        }\n\n        $hasGenerics = (\\count($templates) > 0);\n        $hasAliases = (\\count($aliases) > 0);\n        $isParamConditional = ($returnTypeNode instanceof ConditionalTypeForParameterNode);\n\n        if (! $hasGenerics && ! $hasAliases && ! $isParamConditional && ! ($returnTypeNode instanceof CallableTypeNode)) {\n            $isDynamic = $contract['returnIsDynamic'] ?? (str_contains((string) $returnTypeNode, 'static') || str_contains((string) $returnTypeNode, '$this'));\n\n            if (! $isDynamic) {\n                $resolvedType = self::$resolvedStaticReturnCache[$function] ??= SpecialTypeResolver::resolve($returnTypeNode, $function, null);\n            } else {\n                $resolvedType = SpecialTypeResolver::resolve($returnTypeNode, $function, $thisObj);\n            }\n\n            if ($resolvedType instanceof IdentifierTypeNode) {\n                $lower = strtolower($resolvedType->name);\n                if ($lower === 'mixed' || $lower === 'array') {\n                    return $value;\n                }\n            }\n\n            $err = $registry->validate($value, $resolvedType, 'Return value');\n            if ($err !== null) {\n                return ErrorFactory::createError($function . '(): ' . $err->getMessage());\n            }\n\n            if ($value instanceof Traversable) {\n                $baseName = '';\n                if ($resolvedType instanceof IdentifierTypeNode) {\n                    $baseName = strtolower(ltrim($resolvedType->name, '\\\\'));\n                } elseif ($resolvedType instanceof GenericTypeNode) {\n                    $baseName = strtolower(ltrim($resolvedType->type->name, '\\\\'));\n                }\n\n                if (isset(self::GENERIC_ITERABLES[$baseName])) {\n                    return $wrapIterableCallback($function, 'return', $value);\n                }\n            }\n\n            return $value;\n        }\n\n        $boundTemplates = TemplateManager::getBoundTemplates($function, $thisObj, $templates);\n\n        $sig = null;\n        $boundCount = \\count($boundTemplates);\n        if ($boundCount > 0 && $boundCount <= 2 && ! $isParamConditional && \\count($aliases) === 0 && $thisObj === null) {\n            if ($boundCount === 1) {\n                $first = reset($boundTemplates);\n                $sig = $first instanceof IdentifierTypeNode ? $first->name : (string) $first;\n            } else {\n                $sig = '';\n                foreach ($boundTemplates as $v) {\n                    $sig .= ($v instanceof IdentifierTypeNode ? $v->name : (string) $v) . '|';\n                }\n            }\n\n            if (isset(self::$substitutedReturnCache[$function][$sig])) {\n                $resolvedType = self::$substitutedReturnCache[$function][$sig];\n            }\n        }\n\n        if (! isset($resolvedType)) {\n            $resolvedType = SpecialTypeResolver::resolve($returnTypeNode, $function, $thisObj);\n\n            if ($resolvedType instanceof IdentifierTypeNode && isset($aliases[$resolvedType->name])) {\n                $resolvedType = $aliases[$resolvedType->name];\n            }\n\n            if (\\count($boundTemplates) === 0 && \\count($templates) > 0 && ! $isParamConditional && $thisObj === null) {\n                $resolvedType = self::$unboundReturnCache[$function] ??= SpecialTypeResolver::resolve(\n                    TemplateSubstitutor::substitute($returnTypeNode, [], $templates),\n                    $function,\n                    null\n                );\n            } elseif (\\count($boundTemplates) > 0 || \\count($templates) > 0) {\n                $resolvedType = TemplateSubstitutor::substitute($resolvedType, $boundTemplates, $templates);\n                $resolvedType = SpecialTypeResolver::resolve($resolvedType, $function, $thisObj);\n            }\n\n            $resolvedType = ConditionalChecker::resolve($resolvedType, $vars, $boundTemplates, $registry, $function);\n\n            if ($sig !== null) {\n                self::$substitutedReturnCache[$function][$sig] = $resolvedType;\n            }\n        }\n\n        if ($resolvedType instanceof IdentifierTypeNode) {\n            $lower = strtolower($resolvedType->name);\n            if ($lower === 'mixed' || $lower === 'array') {\n                return $value;\n            }\n        }\n\n        $err = $registry->validate($value, $resolvedType, 'Return value');\n        if ($err !== null) {\n            return ErrorFactory::createError($function . '(): ' . $err->getMessage());\n        }\n\n        if ($resolvedType instanceof CallableTypeNode && CallableWrapper::isCallable($value)) {\n            return CallableWrapper::wrapTypeNode($resolvedType, $value, $function . '(): Return value', $registry);\n        }\n\n        if ($value instanceof Traversable) {\n            $baseName = '';\n            if ($resolvedType instanceof IdentifierTypeNode) {\n                $baseName = strtolower(ltrim($resolvedType->name, '\\\\'));\n            } elseif ($resolvedType instanceof GenericTypeNode) {\n                $baseName = strtolower(ltrim($resolvedType->type->name, '\\\\'));\n            }\n\n            if (isset(self::GENERIC_ITERABLES[$baseName])) {\n                return $wrapIterableCallback($function, 'return', $value);\n            }\n        }\n\n        return $value;\n    }\n}\n","/typephp/src/Internal/Checker/SelfOutChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Checker;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @internal Evaluates generic state transitions on $this (@self-out, @phpstan-self-out, @psalm-self-out).\n */\nfinal class SelfOutChecker\n{\n    /**\n     * O(1) Fast-path cache for methods determined to have no self-out contracts.\n     *\n     * @var array<string, true>\n     */\n    public static array $noSelfOutContractCache = [];\n\n    public static function reset(): void\n    {\n        self::$noSelfOutContractCache = [];\n    }\n\n    /**\n     * @param array<int|string, mixed> $vars\n     */\n    public static function checkSelfOut(\n        string $function,\n        object $thisObj,\n        array $vars,\n        TypeValidatorRegistry $registry,\n        string $effectiveFunction = ''\n    ): void {\n        if (! Config::isEnabled() || ! Config::isSelfOutEnabled()) {\n            return;\n        }\n\n        if (isset(self::$noSelfOutContractCache[$function])) {\n            return;\n        }\n\n        if ($effectiveFunction === '') {\n            $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisObj, $thisObj);\n        }\n\n        if (isset(self::$noSelfOutContractCache[$effectiveFunction])) {\n            self::$noSelfOutContractCache[$function] = true;\n\n            return;\n        }\n\n        $contract = DocblockParser::parse($effectiveFunction);\n\n        if (! ($contract['hasSelfOutContract'] ?? false) || $contract['selfOut'] === null) {\n            self::$noSelfOutContractCache[$effectiveFunction] = true;\n            self::$noSelfOutContractCache[$function] = true;\n\n            return;\n        }\n\n        $selfOutNode = $contract['selfOut'];\n        $allTemplates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n        $boundTemplates = (\\count($allTemplates) > 0)\n            ? TemplateManager::getBoundTemplates($effectiveFunction, $thisObj, $allTemplates)\n            : [];\n\n        if (\\count($boundTemplates) > 0 || \\count($allTemplates) > 0) {\n            $selfOutNode = TemplateSubstitutor::substitute($selfOutNode, $boundTemplates, $allTemplates);\n            $selfOutNode = SpecialTypeResolver::resolve($selfOutNode, $effectiveFunction, $thisObj);\n        }\n\n        if (\n            $selfOutNode instanceof ConditionalTypeForParameterNode ||\n            $selfOutNode instanceof ConditionalTypeNode\n        ) {\n            $selfOutNode = ConditionalChecker::resolve($selfOutNode, $vars, $boundTemplates, $registry, $effectiveFunction);\n        }\n\n        if ($selfOutNode instanceof GenericTypeNode) {\n            TemplateManager::bindInstanceFromNode($thisObj, $selfOutNode, forceBind: true);\n        }\n    }\n}\n","/typephp/src/Internal/Cli/CacheClearCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nuse TypePHP\\Internal\\Io\\CacheManager;\n\n/**\n * @Command Clears the TypePHP cache.\n */\nfinal class CacheClearCommand implements CommandInterface\n{\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n        $count = CacheManager::clear();\n\n        fwrite($outputStream, \"\\n  \" . $c(' TYPEPHP ', 'badge') . ' ' . $c('Cache Clear', 'bold') . \"\\n\\n\");\n        fwrite($outputStream, '  ' . $c('✓', 'green') . ' Cleared ' . $c((string) $count, 'bold') . \" cached file(s).\\n\\n\");\n\n        return 0;\n    }\n}\n","/typephp/src/Internal/Cli/CacheRebuildCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\n/**\n * @internal Rebuilds the TypePHP cache.\n */\nfinal class CacheRebuildCommand implements CommandInterface\n{\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        (new CacheClearCommand())->execute($args, $outputStream, $errorStream);\n        (new CacheWarmCommand())->execute($args, $outputStream, $errorStream);\n\n        return 0;\n    }\n}\n","/typephp/src/Internal/Cli/CacheWarmCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nuse TypePHP\\Internal\\Io\\CacheManager;\n\n/**\n * @internal Warms up the TypePHP cache.\n */\nfinal class CacheWarmCommand implements CommandInterface\n{\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n\n        fwrite($outputStream, '  ' . $c(' TYPEPHP ', 'badge') . ' ' . $c('Cache Warm-Up', 'bold') . \"\\n\\n  \");\n        $dotsInLine = 0;\n\n        $result = CacheManager::warmUp(function (string $status) use (&$dotsInLine, $c, $outputStream) {\n            fwrite($outputStream, $status === 'cached' ? $c('.', 'green') : $c('s', 'gray'));\n            $dotsInLine++;\n            if ($dotsInLine >= 80) {\n                fwrite($outputStream, \"\\n  \");\n                $dotsInLine = 0;\n            }\n        });\n\n        fwrite($outputStream, \"\\n\\n  \" . $c('✓ Cache warm-up complete', 'green') . \"\\n\");\n        fwrite($outputStream, '    ' . $c('•', 'cyan') . ' Scanned:     ' . $c((string) $result['total'], 'bold') . \" file(s)\\n\");\n        fwrite($outputStream, '    ' . $c('•', 'cyan') . ' Transformed: ' . $c((string) $result['cached'], 'bold') . \" file(s)\\n\");\n        fwrite($outputStream, '    ' . $c('•', 'cyan') . ' Skipped:     ' . $c((string) $result['skipped'], 'bold') . \" file(s)\\n\\n\");\n\n        return 0;\n    }\n}\n","/typephp/src/Internal/Cli/CliFormatter.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\n/**\n * @internal Helper class for ANSI color formatting and terminal STDOUT/STDERR output styling.\n */\nfinal class CliFormatter\n{\n    private static bool $vt100Initialized = false;\n\n    public static function initVT100(): void\n    {\n        if (! self::$vt100Initialized) {\n            if (\\function_exists('sapi_windows_vt100_support')) {\n                @sapi_windows_vt100_support(STDOUT, enable: true);\n                @sapi_windows_vt100_support(STDERR, enable: true);\n            }\n            self::$vt100Initialized = true;\n        }\n    }\n\n    public static function color(string $text, string $style = ''): string\n    {\n        self::initVT100();\n\n        $hasColor = (\n            (\\function_exists('sapi_windows_vt100_support') && @sapi_windows_vt100_support(STDOUT)) ||\n            DIRECTORY_SEPARATOR === '/' ||\n            false !== getenv('ANSICON') ||\n            'ON' === getenv('ConEmuANSI') ||\n            false !== getenv('TERM') ||\n            false !== getenv('COLORTERM')\n        ) && false === getenv('NO_COLOR');\n\n        if (! $hasColor || $style === '') {\n            return $text;\n        }\n\n        $styles = [\n            'bold' => \"\\033[1m\",\n            'green' => \"\\033[32m\",\n            'cyan' => \"\\033[36m\",\n            'yellow' => \"\\033[33m\",\n            'red' => \"\\033[31m\",\n            'gray' => \"\\033[90m\",\n            'badge' => \"\\033[44;37;1m\",\n            'badge_red' => \"\\033[41;37;1m\",\n            'badge_green' => \"\\033[42;30;1m\",\n            'reset' => \"\\033[0m\",\n        ];\n\n        return ($styles[$style] ?? '') . $text . $styles['reset'];\n    }\n}\n","/typephp/src/Internal/Cli/CommandInterface.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\n/**\n * @internal Contract defining a CLI command action.\n */\ninterface CommandInterface\n{\n    /**\n     * Executes the command and returns an exit code (0 for success, 1 for error).\n     *\n     * @param array<int, string> $args\n     * @param resource $outputStream\n     * @param resource $errorStream\n     */\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int;\n}\n","/typephp/src/Internal/Cli/CommandRunner.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nfinal class CommandRunner\n{\n    private const KNOWN_COMMANDS = [\n        'config:init',\n        'cache:clear',\n        'cache:warm',\n        'cache:rebuild',\n        'help',\n    ];\n\n    /**\n     * Parses CLI arguments and routes execution to the corresponding command class.\n     *\n     * @param array<int, string> $args\n     * @param resource $outputStream\n     * @param resource $errorStream\n     */\n    public static function run(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n\n        $showHelp = \\in_array('help', $args, strict: true)\n            || \\in_array('typephp:help', $args, strict: true)\n            || \\in_array('--help', $args, strict: true)\n            || \\in_array('-h', $args, strict: true)\n            || $args === [];\n\n        if ($showHelp) {\n            return (new HelpCommand())->execute($args, $outputStream, $errorStream);\n        }\n\n        $firstArg = $args[0] ?? '';\n\n        if ($firstArg === 'config:init' || $firstArg === 'init') {\n            return (new ConfigInitCommand())->execute($args, $outputStream, $errorStream);\n        }\n\n        if ($firstArg === 'cache:rebuild') {\n            return (new CacheRebuildCommand())->execute($args, $outputStream, $errorStream);\n        }\n\n        if ($firstArg === 'cache:clear') {\n            return (new CacheClearCommand())->execute($args, $outputStream, $errorStream);\n        }\n\n        if ($firstArg === 'cache:warm') {\n            return (new CacheWarmCommand())->execute($args, $outputStream, $errorStream);\n        }\n\n        $hasFileExtension = str_contains(basename($firstArg), '.');\n        $isFileTarget = file_exists($firstArg) || $hasFileExtension;\n\n        if (! $isFileTarget) {\n            fwrite($errorStream, \"\\n  \" . $c(' TYPEPHP ', 'badge_red') . ' ' . $c('Error', 'bold') . \"\\n\\n\");\n            fwrite($errorStream, '  ' . $c('✗', 'red') . ' Command ' . $c('\"' . $firstArg . '\"', 'bold') . \" is not defined.\\n\\n\");\n            fwrite($errorStream, '  ' . $c('Did you mean one of these?', 'yellow') . \"\\n\");\n            foreach (self::KNOWN_COMMANDS as $cmd) {\n                fwrite($errorStream, '    ' . $c('•', 'cyan') . ' ' . $cmd . \"\\n\");\n            }\n            fwrite($errorStream, \"\\n\");\n\n            return 1;\n        }\n\n        return (new RunCommand())->execute($args, $outputStream, $errorStream);\n    }\n}\n","/typephp/src/Internal/Cli/ConfigInitCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nfinal class ConfigInitCommand implements CommandInterface\n{\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n        $cwd = getcwd();\n        $targetFile = ($cwd !== false ? $cwd : '.') . '/typephp.php';\n\n        fwrite($outputStream, \"\\n  \" . $c(' TYPEPHP ', 'badge') . ' ' . $c('Configuration Initializer', 'bold') . \"\\n\\n\");\n\n        if (file_exists($targetFile)) {\n            fwrite($outputStream, '  ' . $c('•', 'cyan') . ' Configuration file ' . $c('\"typephp.php\"', 'bold') . \" already exists.\\n\\n\");\n\n            return 0;\n        }\n\n        $template = self::getTemplate();\n        file_put_contents($targetFile, $template);\n\n        fwrite($outputStream, '  ' . $c('✓', 'green') . ' Created ' . $c('\"typephp.php\"', 'bold') . \" in project root directory.\\n\\n\");\n\n        return 0;\n    }\n\n    private static function getTemplate(): string\n    {\n        return <<<'PHP'\n<?php\n\ndeclare(strict_types=1);\n\nreturn [\n    /*\n    |--------------------------------------------------------------------------\n    | Global Master Switch\n    |--------------------------------------------------------------------------\n    | Controls whether TypePHP enforces type checks at runtime.\n    | Set to false for an emergency kill-switch or zero-overhead benchmarking.\n    |\n    | Note on Disabling Approaches:\n    | - Config Switch ('enabled' => false): TypePHP boots normally, but turns all\n    |   runtime checks into instant no-ops (pass-through mode).\n    | - Bootstrap Prevention (TYPEPHP_DISABLE=true): To completely prevent TypePHP\n    |   from booting or registering its stream wrapper during Composer autoload,\n    |   set the environment variable TYPEPHP_DISABLE=true or define('TYPEPHP_DISABLE', true)\n    |   before requiring 'vendor/autoload.php'.\n    */\n    'enabled' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Function Boundary Contracts (@param, @return, @param-out, @self-out)\n    |--------------------------------------------------------------------------\n    | Controls whether function and method parameter, return, and by-reference\n    | out-parameter contracts are enforced at runtime.\n    | When enabled, all parameter and return types (generics, shapes, scalars)\n    | are enforced uniformly to maintain type state consistency.\n    */\n    'params' => true,\n    'returns' => true,\n    'params_out' => true,\n    'self_out' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Strict Generic Return Invariance (PHPStan / Psalm Parity)\n    |--------------------------------------------------------------------------\n    | When true (default / strict), generic return types enforce invariance\n    | matching PHPStan Level MAX. Returning Collection<Dog> when Collection<Animal>\n    | is promised will be rejected unless the class declares '@template-covariant'\n    | or the return type specifies use-site covariance '<covariant Animal>'.\n    |\n    | Set to false (pragmatic mode) when integrating with frameworks like Shopware,\n    | Laravel, or legacy codebases where collection classes omit '@template-covariant'.\n    */\n    'strict_return_generic_invariance' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Vendor Boundary Only Enforcement\n    |--------------------------------------------------------------------------\n    | When true (default), whitelisted vendor packages (e.g. Illuminate\\Collections)\n    | only enforce type contracts on calls originating from application code (included paths).\n    | Internal vendor-to-vendor or vendor-self calls bypass strict enforcement.\n    | Set to false for strict pedantic enforcement across all vendor internals.\n    */\n    'vendor_boundary_only' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Magic Annotations (@property & @method)\n    |--------------------------------------------------------------------------\n    | Enforces class-level annotations for dynamic properties and magic methods\n    | routed through __get, __set, __call, and __callStatic.\n    */\n    'magic_properties' => true,\n    'magic_methods' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Respect Ignore Docblock Tags\n    |--------------------------------------------------------------------------\n    | When true (default), @typephp-ignore and @typephp-ignore-file docblock tags\n    | skip type-checking on specific methods/files. Set to false in CI/CD or\n    | audit runs to force type-checking on all ignored methods without deleting\n    | the docblock tags from source code.\n    */\n    'respect_ignore_tags' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Ignore Tag Stack Trace Depth\n    |--------------------------------------------------------------------------\n    | Controls how many stack frames above a failing type check TypePHP will\n    | inspect to find an enclosing @typephp-ignore or @typephp-disable tag.\n    | Default is 25 frames. Increase this if your application or test suite\n    | uses deep call stacks (e.g. pipelines, middlewares, or nested callers).\n    */\n    'ignore_trace_depth' => 25,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Array Validation Strategy\n    |--------------------------------------------------------------------------\n    | Controls how collections (list<T>, array<K, V>, Type[]) are verified:\n    |\n    | - 'full'   : (Default / Strict) 100% exhaustive scan. Checks every single \n    |             item in every array, guaranteeing every single offending item\n    |             is caught without exception.\n    |\n    | - 'hybrid' : (Beartype O(1) Mode) Fast boundary + random sampling on\n    |             arrays > 128 items. Ideal for massive production datasets.\n    */\n    'array_validation' => 'full',\n\n    /*\n    |--------------------------------------------------------------------------\n    | Respect Native Parameter Nullability\n    |--------------------------------------------------------------------------\n    | When true (default), if a native PHP parameter explicitly declares\n    | nullable syntax (e.g. ?array $param = null), TypePHP permits null even\n    | if the DocBlock author omitted \"|null\" (e.g. @param string[] $param).\n    |\n    | Set to false for strict pedantic enforcement where DocBlocks are the\n    | absolute law and null is rejected unless explicitly typed in the DocBlock.\n    */\n    'respect_native_nullability' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Enable Caching & Cache Directory\n    |--------------------------------------------------------------------------\n    | When enabled, transformed PHP files are cached on disk for speed.\n    | Set to false to run AST transformations purely in RAM (php://memory).\n    |\n    | 'cache_dir' determines where these files are stored. By default (null), \n    | it uses your system's temp directory. You can change this to a path\n    | inside your project, e.g., __DIR__ . '/storage/framework/typephp'.\n    | TypePHP will automatically protect this directory from being re-transformed.\n    */\n    'cache' => true,\n    'cache_dir' => null,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Cache File Modification Monitor\n    |--------------------------------------------------------------------------\n    | When enabled (default), TypePHP checks file modification times (filemtime)\n    | to automatically rebuild the cache when a file changes.\n    | \n    | In production, files do not change. Set this to FALSE to eliminate \n    | hundreds of disk I/O checks per request for maximum performance.\n    | Note: If disabled, you must run `php bin/typephp cache:clear` on deployment.\n    */\n    'cache_check_mtime' => true,\n\n    /*\n    |--------------------------------------------------------------------------\n    | Registered Extensions\n    |--------------------------------------------------------------------------\n    | Explicitly list third-party extension classes that provide path overrides.\n    */\n    'extensions' => [\n        // \\Acme\\Domain\\TypePHPExtension::class,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Stub Files (DocBlock Overrides for Third-Party & Vendor Packages)\n    |--------------------------------------------------------------------------\n    | Path globs or specific file paths containing stub files (.stub, .stub.php, .php)\n    | that override inaccurate or missing DocBlocks in third-party vendor packages.\n    */\n    'stubs' => [\n        // 'stubs/**',\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Inline Variable Validation (@var $x = ...)\n    |--------------------------------------------------------------------------\n    | Fine-grained control over which type categories are enforced on local\n    | variable assignments with inline @var Type $var docblocks.\n    |\n    | Supported options:\n    | - 'properties': Validates class property assignments (e.g. $this->id = 1).\n    | - 'generics'  : Prebinds generic template instances (e.g. Collection<Dog>).\n    | - 'callables' : Wraps inline callbacks (e.g. callable(int): string).\n    | - 'scalars'   : Enforces scalar constraints (e.g. positive-int, non-empty-string).\n    | - 'arrays'    : Enforces array shapes, lists, & typed arrays (e.g. array{id: int}, int[]).\n    | - 'objects'   : Enforces class instance checks (e.g. @var User $user).\n    */\n    'inline_vars' => [\n        'properties' => true,\n        'generics'   => true,\n        'callables'  => true,\n        'scalars'    => true,\n        'arrays'     => true,\n        'objects'    => true,\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Included Paths & Whitelisting\n    |--------------------------------------------------------------------------\n    | Globs or specific file paths that should be intercepted and type-checked.\n    |\n    | Pattern Specificity:\n    | More specific patterns take precedence over broader rules.\n    | You can specify directory globs (e.g. 'src/**'), single vendor packages\n    | (e.g. 'vendor/my-org/my-package/**'), or single specific files\n    | (e.g. 'vendor/monolog/monolog/src/Monolog/Logger.php').\n    */\n    'include' => [\n        'src/**',\n        'app/**',\n        'tests/**',\n        // 'vendor/my-org/my-package/**', // Whitelist a vendor package\n    ],\n\n    /*\n    |--------------------------------------------------------------------------\n    | Excluded Paths & Single-File Blacklisting\n    |--------------------------------------------------------------------------\n    | Globs or specific file paths that should be ignored by the type checker.\n    | You can exclude entire directories (e.g. 'vendor/**') or blacklist\n    | single legacy files inside included directories (e.g. 'src/Legacy/File.php').\n    */\n    'exclude' => [\n        'vendor/**',\n        'storage/**',\n        'var/**',\n        'cache/**',\n        // 'src/Legacy/UnsafeFile.php', // Blacklist a single specific file\n    ],\n];\nPHP;\n    }\n}\n","/typephp/src/Internal/Cli/HelpCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nfinal class HelpCommand implements CommandInterface\n{\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n\n        fwrite($outputStream, \"\\n  \" . $c(' TYPEPHP ', 'badge_green') . ' ' . $c('Runtime Type Checker', 'bold') . \"\\n\\n\");\n        fwrite($outputStream, '  ' . $c('USAGE', 'yellow') . \"\\n\");\n        fwrite($outputStream, \"    vendor/bin/typephp <script.php>\\n\\n\");\n        fwrite($outputStream, '  ' . $c('COMMANDS', 'yellow') . \"\\n\");\n        fwrite($outputStream, '    ' . $c('config:init', 'green') . \"    Generate default typephp.php configuration file\\n\");\n        fwrite($outputStream, '    ' . $c('cache:clear', 'green') . \"    Clear all cached transformed files\\n\");\n        fwrite($outputStream, '    ' . $c('cache:warm', 'green') . \"     Pre-transform and warm up cache for included files\\n\");\n        fwrite($outputStream, '    ' . $c('cache:rebuild', 'green') . \"  Clear and immediately warm up cache\\n\");\n        fwrite($outputStream, '    ' . $c('help', 'green') . \"         Display this help menu\\n\\n\");\n        fwrite($outputStream, '  ' . $c('EXAMPLES', 'yellow') . \"\\n\");\n        fwrite($outputStream, \"    vendor/bin/typephp config:init\\n\");\n        fwrite($outputStream, \"    vendor/bin/typephp index.php\\n\");\n        fwrite($outputStream, \"    vendor/bin/typephp cache:rebuild\\n\\n\");\n\n        return 0;\n    }\n}\n","/typephp/src/Internal/Cli/RunCommand.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Cli;\n\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\TypePHP;\n\n/**\n * @internal Executes TypePHP CLI commands.\n */\nfinal class RunCommand implements CommandInterface\n{\n    private const VALID_PHP_EXTENSIONS = ['php', 'phtml', 'php5', 'php7', 'php8', 'phps'];\n\n    public function execute(array $args, $outputStream = STDOUT, $errorStream = STDERR): int\n    {\n        $c = [CliFormatter::class, 'color'];\n\n        $target = null;\n        $givenTargetCandidate = null;\n\n        foreach ($args as $arg) {\n            if (! str_starts_with($arg, '--') && ! str_starts_with($arg, '-')) {\n                $givenTargetCandidate = $arg;\n                $ext = strtolower(pathinfo($arg, PATHINFO_EXTENSION));\n\n                if ($ext !== '' && ! \\in_array($ext, self::VALID_PHP_EXTENSIONS, strict: true)) {\n                    fwrite($errorStream, \"\\n  \" . $c(' TYPEPHP ', 'badge_red') . ' ' . $c('Error', 'bold') . \"\\n\\n\");\n                    fwrite($errorStream, '  ' . $c('✗', 'red') . ' Target file ' . $c('\"' . $arg . '\"', 'bold') . \" is not a PHP script file. TypePHP can only execute PHP files.\\n\\n\");\n\n                    return 1;\n                }\n\n                if (file_exists($arg)) {\n                    $target = $arg;\n                }\n\n                break;\n            }\n        }\n\n        if ($givenTargetCandidate !== null && $target === null) {\n            fwrite($errorStream, \"\\n  \" . $c(' TYPEPHP ', 'badge_red') . ' ' . $c('Error', 'bold') . \"\\n\\n\");\n            fwrite($errorStream, '  ' . $c('✗', 'red') . ' Target script file ' . $c('\"' . $givenTargetCandidate . '\"', 'bold') . \" does not exist or is not readable.\\n\\n\");\n\n            return 1;\n        }\n\n        if ($target === null) {\n            (new HelpCommand())->execute($args, $outputStream, $errorStream);\n\n            return 1;\n        }\n\n        try {\n            $realTarget = realpath($target);\n            if ($realTarget !== false) {\n                $normalizedTarget = str_replace('\\\\', '/', $realTarget);\n                $currentConfig = Config::get();\n                $includes = [];\n\n                if (\\is_array($currentConfig['include'] ?? null)) {\n                    foreach ($currentConfig['include'] as $inc) {\n                        if (\\is_string($inc)) {\n                            $includes[] = $inc;\n                        }\n                    }\n                }\n\n                $includes[] = $normalizedTarget;\n\n                Config::set([\n                    'include' => array_values(array_unique($includes)),\n                ]);\n            }\n\n            TypePHP::boot();\n\n            if ($realTarget !== false) {\n                require $realTarget;\n            }\n        } catch (\\Throwable $e) {\n            $class = \\get_class($e);\n            $file = $e->getFile();\n            $line = $e->getLine();\n            $msg = $e->getMessage();\n\n            fwrite($errorStream, \"PHP Fatal error:  Uncaught {$class}: {$msg} in {$file} on line {$line}\\n\");\n            fwrite($errorStream, \"Stack trace:\\n\");\n            fwrite($errorStream, \"#0 {main}\\n\");\n            fwrite($errorStream, \"  thrown in {$file} on line {$line}\\n\");\n\n            return 255;\n        }\n\n        return 0;\n    }\n}\n","/typephp/src/Internal/Diagnostic/ErrorFactory.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Diagnostic;\n\nuse ReflectionClass;\nuse TypeError;\n\n/**\n * @internal Factory creating ErrorMessage value objects and preparing TypeError instances with exact caller traces.\n */\nfinal class ErrorFactory\n{\n    private const INTERNAL_DIR_PATTERNS = [\n        'src/Internal/',\n        'bin/typephp',\n    ];\n\n    private const CALL_SITE_KEYWORDS = [\n        'argument $',\n        'argument #',\n        'callback ',\n        'iterator $',\n        'return iterator',\n        'generator sent value',\n        'property ',\n    ];\n\n    /**\n     * Creates an ErrorMessage value object containing formatted type failure details.\n     */\n    public static function createError(string $message): ErrorMessage\n    {\n        if (str_contains($message, 'Return value')) {\n            if (str_ends_with($message, 'null given')) {\n                $message = substr($message, 0, -\\strlen('null given')) . 'none returned';\n            } elseif (str_ends_with($message, ' given')) {\n                $message = substr($message, 0, -\\strlen(' given')) . ' returned';\n            }\n        }\n\n        return new ErrorMessage($message);\n    }\n\n    /**\n     * Prepares a TypeError exception before throwing by filtering internal library frames\n     * and repointing the exception to the actual application caller location.\n     */\n    public static function prepareException(TypeError $e, ?int $line = null, ?string $file = null): TypeError\n    {\n        $targetFile = $file;\n        $targetLine = $line;\n\n        $message = $e->getMessage();\n        $isCallSite = self::isCallSiteError(strtolower($message));\n\n        $filteredTrace = self::filterTrace($e->getTrace(), $isCallSite, $targetFile, $targetLine);\n\n        $sanitizedMessage = self::sanitizeMessage($message, $targetFile, $targetLine);\n\n        self::mutateException($e, $sanitizedMessage, $targetFile, $targetLine, $filteredTrace);\n\n        return $e;\n    }\n\n    /**\n     * Checks if the error message indicates a caller argument or callback error.\n     */\n    private static function isCallSiteError(string $lowerMessage): bool\n    {\n        foreach (self::CALL_SITE_KEYWORDS as $keyword) {\n            if (str_contains($lowerMessage, $keyword)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Filters out internal TypePHP frames from the raw stack trace.\n     *\n     * @param list<array<string, mixed>> $trace\n     *\n     * @return list<array<string, mixed>>\n     */\n    private static function filterTrace(\n        array $trace,\n        bool $isCallSite,\n        ?string &$targetFile,\n        ?int &$targetLine\n    ): array {\n        $filtered = [];\n\n        foreach ($trace as $frame) {\n            $file = isset($frame['file']) && \\is_string($frame['file'])\n                ? str_replace('\\\\', '/', $frame['file'])\n                : '';\n\n            if (self::isInternalFile($file)) {\n                continue;\n            }\n\n            // Sanitize internal closure class prefixes from remaining frames\n            if (isset($frame['class']) && \\is_string($frame['class']) && str_starts_with($frame['class'], 'TypePHP\\\\')) {\n                unset($frame['class'], $frame['type']);\n                $frame['function'] = '{closure}';\n            }\n\n            $filtered[] = $frame;\n\n            if ($isCallSite && $targetFile === null && isset($frame['file'], $frame['line']) && \\is_string($frame['file']) && \\is_int($frame['line'])) {\n                $targetFile = $frame['file'];\n                if ($targetLine === null) {\n                    $targetLine = $frame['line'];\n                }\n            }\n        }\n\n        return $filtered;\n    }\n\n    /**\n     * Determines whether a file path belongs to TypePHP internals.\n     */\n    private static function isInternalFile(string $normalizedFile): bool\n    {\n        if ($normalizedFile === '') {\n            return false;\n        }\n\n        foreach (self::INTERNAL_DIR_PATTERNS as $pattern) {\n            if (str_contains($normalizedFile, $pattern)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Strips internal wrapper paths and CLI runner prefixes from PHP's error message.\n     */\n    private static function sanitizeMessage(string $message, ?string $targetFile, ?int $targetLine): string\n    {\n        if (str_contains($message, 'CallableWrapper.php')) {\n            $cleaned = (string) preg_replace('/, called in .*?CallableWrapper\\.php on line \\d+/i', '', $message);\n            if ($targetFile !== null && $targetLine !== null) {\n                $cleaned .= \", called in {$targetFile} on line {$targetLine}\";\n            }\n            $message = $cleaned;\n        }\n\n        return str_replace('TypePHP\\Internal\\Cli\\RunCommand::', '', $message);\n    }\n\n    /**\n     * Uses reflection on base \\Error to mutate private properties safely.\n     *\n     * @param list<array<string, mixed>> $filteredTrace\n     */\n    private static function mutateException(\n        TypeError $e,\n        string $message,\n        ?string $targetFile,\n        ?int $targetLine,\n        array $filteredTrace\n    ): void {\n        $ref = new ReflectionClass(\\Error::class);\n\n        $propMessage = $ref->getProperty('message');\n        $propMessage->setValue($e, $message);\n\n        if ($targetFile !== null) {\n            $propFile = $ref->getProperty('file');\n            $propFile->setValue($e, $targetFile);\n        }\n\n        if ($targetLine !== null) {\n            $propLine = $ref->getProperty('line');\n            $propLine->setValue($e, $targetLine);\n        }\n\n        if (\\count($filteredTrace) > 0) {\n            $propTrace = $ref->getProperty('trace');\n            $propTrace->setValue($e, $filteredTrace);\n        }\n    }\n}\n","/typephp/src/Internal/Diagnostic/ErrorMessage.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Diagnostic;\n\n/**\n * @internal Value object holding validation error messages prior to call-site exception throwing.\n */\nfinal class ErrorMessage\n{\n    public function __construct(private string $message)\n    {\n    }\n\n    public function getMessage(): string\n    {\n        return $this->message;\n    }\n}\n","/typephp/src/Internal/Diagnostic/TypeFormatter.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Diagnostic;\n\n/**\n * @internal\n */\nfinal class TypeFormatter\n{\n    public static function formatGivenValue(mixed $value, bool $isSensitive = false): string\n    {\n        if ($isSensitive) {\n            return get_debug_type($value);\n        }\n\n        if (\\is_int($value)) {\n            if ($value < 0) {\n                return \"negative int ($value)\";\n            }\n            if ($value === 0) {\n                return 'zero int (0)';\n            }\n\n            return \"int ($value)\";\n        }\n\n        if (\\is_float($value)) {\n            return \"float ($value)\";\n        }\n\n        if (\\is_string($value)) {\n            if ($value === '') {\n                return \"empty string ('')\";\n            }\n            if (\\strlen($value) > 20) {\n                return \"string '\" . substr($value, 0, 17) . \"...'\";\n            }\n\n            return \"string '$value'\";\n        }\n\n        if (\\is_array($value)) {\n            if (\\count($value) === 0) {\n                return 'empty array ([])';\n            }\n            if (array_is_list($value)) {\n                return 'list (' . \\count($value) . ' items)';\n            }\n\n            $keys = array_keys($value);\n            $firstStringKey = null;\n            $firstNonSequentialIndex = null;\n\n            foreach ($keys as $idx => $key) {\n                if (\\is_string($key)) {\n                    $firstStringKey = $key;\n\n                    break;\n                }\n                if ($key !== $idx && $firstNonSequentialIndex === null) {\n                    $firstNonSequentialIndex = $key;\n                }\n            }\n\n            if ($firstStringKey !== null) {\n                return \"associative array (key '$firstStringKey')\";\n            }\n\n            return \"non-sequential array (index $firstNonSequentialIndex)\";\n        }\n\n        if (\\is_bool($value)) {\n            return $value ? 'bool (true)' : 'bool (false)';\n        }\n\n        return get_debug_type($value);\n    }\n}\n","/typephp/src/Internal/Docblock/DocblockExtractor.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Docblock;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\GenericTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\Parser\\ConstExprParser;\nuse PHPStan\\PhpDocParser\\Parser\\PhpDocParser;\nuse PHPStan\\PhpDocParser\\Parser\\TokenIterator;\nuse PHPStan\\PhpDocParser\\Parser\\TypeParser;\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\nuse TypePHP\\Internal\\Util\\StubManager;\n\n/**\n * @internal Encapsulates PHPDoc AST parsing, tokenizing, and tag extractions.\n */\nfinal class DocblockExtractor\n{\n    /**\n     * In-memory cache for normalized and parsed PhpDocNode ASTs keyed by raw docblock string.\n     *\n     * @var array<string, PhpDocNode>\n     */\n    private static array $docParseCache = [];\n\n    private static ?PhpDocParser $phpDocParser = null;\n\n    private static ?TypeParser $typeParser = null;\n\n    private static ?Lexer $lexer = null;\n\n    /**\n     * Resets the parsed docblock cache. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$docParseCache = [];\n    }\n\n    /**\n     * Returns shared static instances of PHPStan's PhpDocParser and Lexer.\n     *\n     * @return array{PhpDocParser, Lexer}\n     */\n    public static function getParserComponents(): array\n    {\n        self::initParserComponents();\n\n        /** @var PhpDocParser $docParser */\n        $docParser = self::$phpDocParser;\n        /** @var Lexer $lexer */\n        $lexer = self::$lexer;\n\n        return [$docParser, $lexer];\n    }\n\n    /**\n     * Returns shared static instances of PHPStan's TypeParser and Lexer.\n     *\n     * @return array{TypeParser, Lexer}\n     */\n    public static function getTypeParserComponents(): array\n    {\n        self::initParserComponents();\n\n        /** @var TypeParser $typeParser */\n        $typeParser = self::$typeParser;\n        /** @var Lexer $lexer */\n        $lexer = self::$lexer;\n\n        return [$typeParser, $lexer];\n    }\n\n    private static function initParserComponents(): void\n    {\n        if (self::$phpDocParser === null || self::$typeParser === null || self::$lexer === null) {\n            $config = new ParserConfig(usedAttributes: []);\n            self::$lexer = new Lexer($config);\n            $constExprParser = new ConstExprParser($config);\n            self::$typeParser = new TypeParser($config, $constExprParser);\n            self::$phpDocParser = new PhpDocParser($config, self::$typeParser, $constExprParser);\n        }\n    }\n\n    /**\n     * Normalizes and parses a PHPDoc doccomment string into an AST PhpDocNode with in-memory memoization.\n     */\n    public static function parseDocString(string $doc): PhpDocNode\n    {\n        if (isset(self::$docParseCache[$doc])) {\n            return self::$docParseCache[$doc];\n        }\n\n        $normalized = DocblockNormalizer::normalize($doc);\n        [$phpDocParser, $lexer] = self::getParserComponents();\n        $tokens = new TokenIterator($lexer->tokenize($normalized));\n\n        return self::$docParseCache[$doc] = $phpDocParser->parse($tokens);\n    }\n\n    /**\n     * Extracts parameter tags with priority: @phpstan-param > @psalm-param > @param.\n     *\n     * @return array<string, ParamTagValueNode>\n     */\n    public static function getParamTags(PhpDocNode $node): array\n    {\n        $tags = [];\n\n        foreach ($node->getParamTagValues('@param') as $tag) {\n            $pName = ltrim($tag->parameterName, '$');\n            $tags[$pName] = $tag;\n        }\n\n        foreach ($node->getParamTagValues('@psalm-param') as $tag) {\n            $pName = ltrim($tag->parameterName, '$');\n            $tags[$pName] = $tag;\n        }\n\n        foreach ($node->getParamTagValues('@phpstan-param') as $tag) {\n            $pName = ltrim($tag->parameterName, '$');\n            $tags[$pName] = $tag;\n        }\n\n        return $tags;\n    }\n\n    /**\n     * Extracts parameter-out tags with priority: @phpstan-param-out > @psalm-param-out > @param-out.\n     *\n     * @return array<string, ParamOutTagValueNode>\n     */\n    public static function getParamOutTags(PhpDocNode $node): array\n    {\n        $tags = [];\n\n        foreach ($node->getTagsByName('@param-out') as $tag) {\n            if ($tag->value instanceof ParamOutTagValueNode) {\n                $pName = ltrim($tag->value->parameterName, '$');\n                $tags[$pName] = $tag->value;\n            }\n        }\n\n        foreach ($node->getTagsByName('@psalm-param-out') as $tag) {\n            if ($tag->value instanceof ParamOutTagValueNode) {\n                $pName = ltrim($tag->value->parameterName, '$');\n                $tags[$pName] = $tag->value;\n            }\n        }\n\n        foreach ($node->getTagsByName('@phpstan-param-out') as $tag) {\n            if ($tag->value instanceof ParamOutTagValueNode) {\n                $pName = ltrim($tag->value->parameterName, '$');\n                $tags[$pName] = $tag->value;\n            }\n        }\n\n        return $tags;\n    }\n\n    /**\n     * Extracts self-out / this-out tags with priority: @phpstan-* > @psalm-* > standard.\n     */\n    public static function getSelfOutTag(PhpDocNode $node): ?TypeNode\n    {\n        $phpstanTags = [\n            ...$node->getTagsByName('@phpstan-self-out'),\n            ...$node->getTagsByName('@phpstan-this-out'),\n        ];\n        foreach ($phpstanTags as $tag) {\n            if ($tag->value instanceof SelfOutTagValueNode) {\n                return $tag->value->type;\n            }\n        }\n\n        $psalmTags = [\n            ...$node->getTagsByName('@psalm-self-out'),\n            ...$node->getTagsByName('@psalm-this-out'),\n        ];\n        foreach ($psalmTags as $tag) {\n            if ($tag->value instanceof SelfOutTagValueNode) {\n                return $tag->value->type;\n            }\n        }\n\n        $standardTags = [\n            ...$node->getTagsByName('@self-out'),\n            ...$node->getTagsByName('@this-out'),\n        ];\n        foreach ($standardTags as $tag) {\n            if ($tag->value instanceof SelfOutTagValueNode) {\n                return $tag->value->type;\n            }\n            if ($tag->value instanceof GenericTagValueNode) {\n                try {\n                    [$typeParser, $lexer] = self::getTypeParserComponents();\n                    $tokens = new TokenIterator($lexer->tokenize($tag->value->value));\n\n                    return $typeParser->parse($tokens);\n                } catch (\\Throwable $e) {\n                    // Silently ignore malformed tags\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Extracts return tag with priority: @phpstan-return > @psalm-return > @return.\n     */\n    public static function getReturnTag(PhpDocNode $node): ?ReturnTagValueNode\n    {\n        $phpstanReturns = $node->getReturnTagValues('@phpstan-return');\n        if (\\count($phpstanReturns) > 0) {\n            return $phpstanReturns[0];\n        }\n\n        $psalmReturns = $node->getReturnTagValues('@psalm-return');\n        if (\\count($psalmReturns) > 0) {\n            return $psalmReturns[0];\n        }\n\n        $returns = $node->getReturnTagValues('@return');\n        if (\\count($returns) > 0) {\n            return $returns[0];\n        }\n\n        return null;\n    }\n\n    /**\n     * Extracts @var tags with priority per variable name: @phpstan-var > @psalm-var > @var.\n     *\n     * @return array<VarTagValueNode>\n     */\n    public static function getVarTags(PhpDocNode $node): array\n    {\n        $named = [];\n\n        foreach ($node->getVarTagValues('@var') as $tag) {\n            $vName = ltrim($tag->variableName, '$');\n            if ($vName !== '') {\n                $named[$vName] = $tag;\n            }\n        }\n\n        foreach ($node->getVarTagValues('@psalm-var') as $tag) {\n            $vName = ltrim($tag->variableName, '$');\n            if ($vName !== '') {\n                $named[$vName] = $tag;\n            }\n        }\n\n        foreach ($node->getVarTagValues('@phpstan-var') as $tag) {\n            $vName = ltrim($tag->variableName, '$');\n            if ($vName !== '') {\n                $named[$vName] = $tag;\n            }\n        }\n\n        $unnamed = [];\n        $unnamedPhpstan = array_values(array_filter($node->getVarTagValues('@phpstan-var'), fn ($t) => $t->variableName === ''));\n        $unnamedPsalm = array_values(array_filter($node->getVarTagValues('@psalm-var'), fn ($t) => $t->variableName === ''));\n        $unnamedStandard = array_values(array_filter($node->getVarTagValues('@var'), fn ($t) => $t->variableName === ''));\n\n        if (\\count($unnamedPhpstan) > 0) {\n            $unnamed = $unnamedPhpstan;\n        } elseif (\\count($unnamedPsalm) > 0) {\n            $unnamed = $unnamedPsalm;\n        } elseif (\\count($unnamedStandard) > 0) {\n            $unnamed = $unnamedStandard;\n        }\n\n        return array_values([...$named, ...$unnamed]);\n    }\n\n    /**\n     * Extracts all @template tags with priority: @phpstan-template-* > @psalm-template-* > @template-*.\n     *\n     * @return array<string, TemplateTagValueNode>\n     */\n    public static function extractTemplates(PhpDocNode $node): array\n    {\n        $templates = [];\n\n        $priorityGroups = [\n            ['@template', '@template-covariant', '@template-contravariant'],\n            ['@psalm-template', '@psalm-template-covariant', '@psalm-template-contravariant'],\n            ['@phpstan-template', '@phpstan-template-covariant', '@phpstan-template-contravariant'],\n        ];\n\n        foreach ($priorityGroups as $tagNames) {\n            foreach ($tagNames as $tagName) {\n                foreach ($node->getTagsByName($tagName) as $tagNode) {\n                    if ($tagNode->value instanceof TemplateTagValueNode) {\n                        $templates[$tagNode->value->name] = $tagNode->value;\n                    }\n                }\n            }\n        }\n\n        return $templates;\n    }\n\n    /**\n     * Extracts declared template variances ('covariant', 'contravariant', or 'invariant') per template name.\n     *\n     * @return array<string, string>\n     */\n    public static function extractTemplateVariances(PhpDocNode $node): array\n    {\n        $variances = [];\n\n        $priorityGroups = [\n            ['@template', '@template-covariant', '@template-contravariant'],\n            ['@psalm-template', '@psalm-template-covariant', '@psalm-template-contravariant'],\n            ['@phpstan-template', '@phpstan-template-covariant', '@phpstan-template-contravariant'],\n        ];\n\n        foreach ($priorityGroups as $tagNames) {\n            foreach ($tagNames as $tagName) {\n                foreach ($node->getTagsByName($tagName) as $tagNode) {\n                    if ($tagNode->value instanceof TemplateTagValueNode) {\n                        $tName = $tagNode->value->name;\n                        $lowerTag = strtolower($tagNode->name);\n\n                        if (str_contains($lowerTag, 'covariant')) {\n                            $variances[$tName] = 'covariant';\n                        } elseif (str_contains($lowerTag, 'contravariant')) {\n                            $variances[$tName] = 'contravariant';\n                        } else {\n                            $variances[$tName] = 'invariant';\n                        }\n                    }\n                }\n            }\n        }\n\n        return $variances;\n    }\n\n    /**\n     * Extracts all inherited template type tags (@extends, @implements, @use and their @template-*, @phpstan-*, @psalm-* variants).\n     *\n     * @return array<int, \\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode|\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode|\\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode>\n     */\n    public static function getInheritedTags(PhpDocNode $node): array\n    {\n        $tags = [];\n        $tagNames = [\n            '@extends',\n            '@template-extends',\n            '@phpstan-extends',\n            '@psalm-extends',\n            '@implements',\n            '@template-implements',\n            '@phpstan-implements',\n            '@psalm-implements',\n            '@use',\n            '@template-use',\n            '@phpstan-use',\n        ];\n\n        foreach ($tagNames as $name) {\n            foreach ($node->getTagsByName($name) as $tagNode) {\n                if (\n                    $tagNode->value instanceof \\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode ||\n                    $tagNode->value instanceof \\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode ||\n                    $tagNode->value instanceof \\PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode\n                ) {\n                    $tags[] = $tagNode->value;\n                }\n            }\n        }\n\n        return $tags;\n    }\n\n    /**\n     * Extracts a TypeNode from a property's @var, @param, @phpstan-param, or @psalm-param docblock.\n     */\n    public static function extractTypeFromPropertyDoc(string $doc, string $propName): ?TypeNode\n    {\n        try {\n            $phpDocNode = self::parseDocString($doc);\n\n            foreach (self::getVarTags($phpDocNode) as $varTag) {\n                $tagVarName = ltrim($varTag->variableName, '$');\n                if ($tagVarName === '' || $tagVarName === $propName) {\n                    return $varTag->type;\n                }\n            }\n\n            foreach (self::getParamTags($phpDocNode) as $tagParamName => $paramTag) {\n                if ($tagParamName === '' || $tagParamName === $propName) {\n                    return $paramTag->type;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed property docblocks\n        }\n\n        return null;\n    }\n\n    /**\n     * Extracts the first @var tag's type string and variable name from a docblock string.\n     *\n     * @return array{0: string, 1: string}|null\n     */\n    public static function extractVarTagFromDoc(string $doc): ?array\n    {\n        try {\n            $phpDocNode = self::parseDocString($doc);\n            $varTags = self::getVarTags($phpDocNode);\n            if (\\count($varTags) > 0) {\n                $typeString = (string) $varTags[0]->type;\n                $varName = ltrim($varTags[0]->variableName, '$');\n\n                return [$typeString, $varName];\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed docblocks\n        }\n\n        return null;\n    }\n\n    /**\n        * Extracts local and imported type aliases (@phpstan-type/@psalm-type and @phpstan-import-type/@psalm-import-type) from a PHPDoc node.\n        * Prioritizes @phpstan-* > @psalm-* within the same docblock, and child class overrides over parent classes across inheritance.\n        *\n         * @param array<string, TypeNode> $aliases\n         * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod $ref\n        */\n    public static function extractAliases(\n        PhpDocNode $phpDocNode,\n        array &$aliases,\n        \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod $ref\n    ): void {\n        $currentDocAliases = [];\n\n        foreach ($phpDocNode->getTagsByName('@psalm-type') as $tag) {\n            if ($tag->value instanceof TypeAliasTagValueNode) {\n                $currentDocAliases[$tag->value->alias] = $tag->value->type;\n            }\n        }\n\n        foreach ($phpDocNode->getTagsByName('@phpstan-type') as $tag) {\n            if ($tag->value instanceof TypeAliasTagValueNode) {\n                $currentDocAliases[$tag->value->alias] = $tag->value->type;\n            }\n        }\n\n        foreach ($currentDocAliases as $name => $type) {\n            if (! isset($aliases[$name])) {\n                $aliases[$name] = $type;\n            }\n        }\n\n        $importTags = [\n            ...$phpDocNode->getTagsByName('@psalm-import-type'),\n            ...$phpDocNode->getTagsByName('@phpstan-import-type'),\n        ];\n\n        foreach ($importTags as $tag) {\n            if ($tag->value instanceof TypeAliasImportTagValueNode) {\n                $importTag = $tag->value;\n                $localName = $importTag->importedAs ?? $importTag->importedAlias;\n\n                if (! isset($aliases[$localName])) {\n                    $fqcnSource = SpecialTypeResolver::resolveFqcn($importTag->importedFrom->name, $ref);\n                    $resolvedType = self::resolveImportedTypeAlias($fqcnSource, $importTag->importedAlias);\n                    if ($resolvedType !== null) {\n                        $aliases[$localName] = $resolvedType;\n                    }\n                }\n            }\n        }\n\n        foreach ($aliases as $name => $type) {\n            $aliases[$name] = DocblockParser::substituteAliases($type, $aliases);\n        }\n    }\n\n    /**\n     * Resolves an imported type alias (@phpstan-import-type / @psalm-import-type) from a target class, interface, trait, or enum.\n     */\n    public static function resolveImportedTypeAlias(string $fqcn, string $importedAlias): ?TypeNode\n    {\n        if (! ClassNameValidator::isValid($fqcn) || (! class_exists($fqcn) && ! interface_exists($fqcn) && ! trait_exists($fqcn) && ! enum_exists($fqcn))) {\n            return null;\n        }\n\n        try {\n            $stubDoc = StubManager::getClassDoc($fqcn);\n            $ref = new \\ReflectionClass($fqcn);\n            $doc = $stubDoc ?? $ref->getDocComment();\n\n            if ($doc !== false && $doc !== null) {\n                $phpDocNode = self::parseDocString($doc);\n\n                $targetAliases = [];\n                self::extractAliases($phpDocNode, $targetAliases, $ref);\n\n                if (isset($targetAliases[$importedAlias])) {\n                    return $targetAliases[$importedAlias];\n                }\n\n                $importTags = [\n                    ...$phpDocNode->getTagsByName('@psalm-import-type'),\n                    ...$phpDocNode->getTagsByName('@phpstan-import-type'),\n                ];\n\n                foreach ($importTags as $tag) {\n                    if ($tag->value instanceof TypeAliasImportTagValueNode) {\n                        $importTag = $tag->value;\n                        $localName = $importTag->importedAs ?? $importTag->importedAlias;\n                        if ($localName === $importedAlias) {\n                            $nextFqcn = SpecialTypeResolver::resolveFqcn($importTag->importedFrom->name, $ref);\n\n                            return self::resolveImportedTypeAlias($nextFqcn, $importTag->importedAlias);\n                        }\n                    }\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore unresolvable types\n        }\n\n        return null;\n    }\n\n    /**\n     * Extracts a TypeNode from a class-level @property, @property-read, or @property-write docblock.\n     */\n    public static function extractTypeFromClassPropertyDoc(string $doc, string $propName): ?TypeNode\n    {\n        try {\n            $phpDocNode = self::parseDocString($doc);\n\n            foreach ($phpDocNode->getPropertyTagValues() as $tag) {\n                if (ltrim($tag->propertyName, '$') === $propName) {\n                    return $tag->type;\n                }\n            }\n\n            foreach ($phpDocNode->getPropertyWriteTagValues() as $tag) {\n                if (ltrim($tag->propertyName, '$') === $propName) {\n                    return $tag->type;\n                }\n            }\n\n            foreach ($phpDocNode->getPropertyReadTagValues() as $tag) {\n                if (ltrim($tag->propertyName, '$') === $propName) {\n                    return $tag->type;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed class docblocks\n        }\n\n        return null;\n    }\n\n    /**\n     * Extracts a MethodTagValueNode from a class-level @method docblock.\n     */\n    public static function extractMagicMethodContract(string $doc, string $methodName): ?MethodTagValueNode\n    {\n        try {\n            $phpDocNode = self::parseDocString($doc);\n            foreach ($phpDocNode->getMethodTagValues() as $tag) {\n                if ($tag->methodName === $methodName) {\n                    return $tag;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed class docblocks\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Docblock/DocblockNormalizer.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Docblock;\n\n/**\n * Normalizes PHPDoc comment strings before AST parsing.\n * Converts class-specific shapes like stdClass{id: int} into intersection shapes (stdClass & object{id: int}).\n * Normalizes variadic tuple spread syntax (...Type[] and ...list<Type>) into PHPStan-compliant ...<Type> syntax.\n *\n * @internal\n */\nfinal class DocblockNormalizer\n{\n    /**\n     * Built-in PHPStan shape keywords that should remain un-wrapped.\n     */\n    private const BUILTIN_SHAPE_KEYWORDS = [\n        'array',\n        'list',\n        'non-empty-array',\n        'non-empty-list',\n        'object',\n    ];\n\n    /**\n     * Normalizes custom class shapes inside docblock text into PHPStan-compatible intersection shapes.\n     * Uses fast string guards to bypass regex execution when special patterns are absent.\n     */\n    public static function normalize(string $doc): string\n    {\n        if (! str_contains($doc, '@')) {\n            return $doc;\n        }\n\n        if (str_contains($doc, '-type') && str_contains($doc, '=')) {\n            $doc = preg_replace('/(@(?:phpstan|psalm)-type\\s+[a-zA-Z0-9_\\x80-\\xff]+)\\s*=\\s*/', '$1 ', $doc) ?? $doc;\n        }\n\n        if (str_contains($doc, '@self-out') && ! str_contains($doc, '@phpstan-self-out') && ! str_contains($doc, '@psalm-self-out')) {\n            $doc = preg_replace('/@self-out\\b/', '@phpstan-self-out', $doc) ?? $doc;\n        }\n\n        if (str_contains($doc, '@this-out') && ! str_contains($doc, '@phpstan-this-out') && ! str_contains($doc, '@psalm-this-out')) {\n            $doc = preg_replace('/@this-out\\b/', '@phpstan-this-out', $doc) ?? $doc;\n        }\n\n        if (str_contains($doc, 'callable') || str_contains($doc, 'Closure')) {\n            $doc = preg_replace('/(callable|Closure)\\s*\\(([^)]*)\\)(?!\\s*:)/', '$1($2): mixed', $doc) ?? $doc;\n        }\n\n        if (str_contains($doc, '::') && str_contains($doc, ':')) {\n            $doc = preg_replace('/(\\\\\\\\?[a-zA-Z_\\x80-\\xff][\\\\\\\\a-zA-Z0-9_\\x80-\\xff]*::[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)\\s*(\\??:)/', '\"$1\"$2', $doc) ?? $doc;\n        }\n\n        if (str_contains($doc, '...')) {\n            $doc = preg_replace('/(\\.\\.\\.\\s*)([a-zA-Z0-9_\\x80-\\xff\\\\\\\\]+)\\[\\]/', '$1<$2>', $doc) ?? $doc;\n            $doc = preg_replace('/(\\.\\.\\.\\s*)(?:list|array)<([^>]+)>/', '$1<$2>', $doc) ?? $doc;\n        }\n\n        if (! str_contains($doc, '{')) {\n            return $doc;\n        }\n\n        return self::normalizeShapes($doc);\n    }\n\n    /**\n     * Normalizes custom class shapes supporting arbitrary nested balanced braces via PCRE recursion.\n     */\n    private static function normalizeShapes(string $doc): string\n    {\n        $pattern = '/(\\\\\\\\?[a-zA-Z_\\x80-\\xff][\\\\\\\\a-zA-Z0-9_\\x80-\\xff]*)\\s*\\{((?:[^{}]+|\\{(?2)\\})*)\\}/s';\n\n        return preg_replace_callback(\n            $pattern,\n            function (array $matches): string {\n                $className = $matches[1];\n                $shapeBody = self::normalizeShapes($matches[2]);\n\n                $lower = strtolower(ltrim($className, '\\\\'));\n                if (\\in_array($lower, self::BUILTIN_SHAPE_KEYWORDS, strict: true)) {\n                    return $className . '{' . $shapeBody . '}';\n                }\n\n                return '(' . $className . '&object{' . $shapeBody . '})';\n            },\n            $doc\n        ) ?? $doc;\n    }\n}\n","/typephp/src/Internal/Docblock/DocblockParser.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Docblock;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse TypePHP\\Internal\\Checker\\InlineChecker;\nuse TypePHP\\Internal\\Resolver\\HierarchyResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\FileFilter;\nuse TypePHP\\Internal\\Util\\StubManager;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * @phpstan-type FunctionContract array{\n *     types: array<string, TypeNode>,\n *     paramOuts: array<string, TypeNode>,\n *     selfOut: ?TypeNode,\n *     templates: array<string, TemplateTagValueNode>,\n *     classTemplates: array<string, TemplateTagValueNode>,\n *     allTemplates?: array<string, TemplateTagValueNode>,\n *     return: ?TypeNode,\n *     aliases: array<string, TypeNode>,\n *     sensitiveParams: array<string, bool>,\n *     hasParamContract: bool,\n *     hasParamOutContract: bool,\n *     hasSelfOutContract: bool,\n *     hasReturnContract: bool,\n *     paramsUseGenerics: bool,\n *     returnUsesGenerics: bool,\n *     returnUsesMethodTemplates: bool,\n *     returnIsThis: bool,\n *     returnIsDynamic: bool,\n *     allParamsUnconstrained: bool,\n *     returnUnconstrained: bool,\n *     isSimple: bool\n * }\n *\n * @internal Main orchestrator parsing and caching PHPDoc contracts (@param, @param-out, @return, @template, @phpstan-type, @var, stubs).\n */\nfinal class DocblockParser\n{\n    /**\n     * Cache for resolved contract metadata.\n     *\n     * @var array<string, FunctionContract>\n     */\n    private static array $cache = [];\n\n    /**\n     * 2D Cache for resolved class property types: [$className][$propertyName] => ?TypeNode.\n     *\n     * @var array<string, array<string, ?TypeNode>>\n     */\n    private static array $propertyCache = [];\n\n    /**\n     * 2D Cache for resolved magic method contracts: [$className][$methodName] => ?array{...}.\n     *\n     * @var array<string, array<string, ?array{return: ?TypeNode, parameters: array<int, array{name: string, type: ?TypeNode, isVariadic: bool, isOptional: bool}>, aliases: array<string, TypeNode>, templates: array<string, TemplateTagValueNode>}>>\n     */\n    private static array $magicMethodCache = [];\n\n    /**\n     * In-memory cache for class-level templates and aliases per class name.\n     *\n     * @var array<string, array{templates: array<string, TemplateTagValueNode>, aliases: array<string, TypeNode>}>\n     */\n    private static array $classLevelDocCache = [];\n\n    /**\n     * Fast O(1) lookup matrix for scalar refinements compatible with PHP native built-in types.\n     *\n     * @var array<string, array<string, bool>>\n     */\n    private const BUILTIN_REFINEMENTS = [\n        'int' => [\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n        ],\n        'integer' => [\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n        ],\n        'string' => [\n            'non-empty-string' => true,\n            'numeric-string' => true,\n            'lowercase-string' => true,\n            'non-empty-lowercase-string' => true,\n            'uppercase-string' => true,\n            'non-empty-uppercase-string' => true,\n            'class-string' => true,\n            'interface-string' => true,\n            'trait-string' => true,\n            'enum-string' => true,\n            'callable-string' => true,\n            'literal-string' => true,\n            'truthy-string' => true,\n            'non-falsy-string' => true,\n        ],\n        'float' => [\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n            'double' => true,\n        ],\n        'double' => [\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n            'double' => true,\n        ],\n        'bool' => [\n            'true' => true,\n            'false' => true,\n            'boolean' => true,\n        ],\n        'boolean' => [\n            'true' => true,\n            'false' => true,\n            'boolean' => true,\n        ],\n    ];\n\n    /**\n     * Resets the contract, property, and class-level docblock caches.\n     */\n    public static function reset(): void\n    {\n        self::$cache = [];\n        self::$propertyCache = [];\n        self::$magicMethodCache = [];\n        self::$classLevelDocCache = [];\n        InlineChecker::reset();\n        DocblockExtractor::reset();\n        FileFilter::reset();\n        TypeValidatorRegistry::reset();\n        StubManager::reset();\n        SpecialTypeResolver::reset();\n    }\n\n    /**\n     * Checks recursively whether an AST TypeNode references any declared generic templates.\n     *\n     * @param array<string, mixed> $templateNames\n     */\n    public static function typeReferencesTemplate(?TypeNode $node, array $templateNames): bool\n    {\n        if ($node === null || $templateNames === []) {\n            return false;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            return isset($templateNames[$node->name]);\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            if (isset($templateNames[$node->type->name])) {\n                return true;\n            }\n            foreach ($node->genericTypes as $gt) {\n                if (self::typeReferencesTemplate($gt, $templateNames)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($node instanceof ConditionalTypeNode) {\n            return self::typeReferencesTemplate($node->subjectType, $templateNames)\n                || self::typeReferencesTemplate($node->targetType, $templateNames)\n                || self::typeReferencesTemplate($node->if, $templateNames)\n                || self::typeReferencesTemplate($node->else, $templateNames);\n        }\n\n        if ($node instanceof ConditionalTypeForParameterNode) {\n            return self::typeReferencesTemplate($node->targetType, $templateNames)\n                || self::typeReferencesTemplate($node->if, $templateNames)\n                || self::typeReferencesTemplate($node->else, $templateNames);\n        }\n\n        if ($node instanceof OffsetAccessTypeNode) {\n            return self::typeReferencesTemplate($node->type, $templateNames)\n                || self::typeReferencesTemplate($node->offset, $templateNames);\n        }\n\n        if ($node instanceof ArrayTypeNode || $node instanceof NullableTypeNode) {\n            return self::typeReferencesTemplate($node->type, $templateNames);\n        }\n\n        if ($node instanceof UnionTypeNode || $node instanceof IntersectionTypeNode) {\n            foreach ($node->types as $t) {\n                if (self::typeReferencesTemplate($t, $templateNames)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            foreach ($node->items as $item) {\n                if (self::typeReferencesTemplate($item->valueType, $templateNames)) {\n                    return true;\n                }\n            }\n\n            if ($node->unsealedType !== null) {\n                if ($node->unsealedType->keyType !== null && self::typeReferencesTemplate($node->unsealedType->keyType, $templateNames)) {\n                    return true;\n                }\n\n                return self::typeReferencesTemplate($node->unsealedType->valueType, $templateNames);\n            }\n\n            return false;\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            foreach ($node->items as $item) {\n                if (self::typeReferencesTemplate($item->valueType, $templateNames)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            foreach ($node->parameters as $p) {\n                if (self::typeReferencesTemplate($p->type, $templateNames)) {\n                    return true;\n                }\n            }\n\n            return self::typeReferencesTemplate($node->returnType, $templateNames);\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if a TypeNode represents an unconstrained type (mixed or array).\n     */\n    private static function isUnconstrainedType(TypeNode $typeNode): bool\n    {\n        if (! ($typeNode instanceof IdentifierTypeNode)) {\n            return false;\n        }\n        $lower = strtolower($typeNode->name);\n\n        return $lower === 'mixed' || $lower === 'array';\n    }\n\n    /**\n     * Computes pre-optimized flags for a contract to avoid redundant re-parsing.\n     *\n     * @param array<string, TypeNode> $types\n     * @param array<string, TypeNode> $aliases\n     * @param array<string, TemplateTagValueNode> $methodTemplates\n     *\n     * @return array{allParamsUnconstrained: bool, returnUnconstrained: bool, isSimple: bool}\n     */\n    private static function computeContractFlags(\n        array $types,\n        ?TypeNode $returnType,\n        bool $paramsUseGenerics,\n        bool $returnUsesGenerics,\n        array $aliases,\n        array $methodTemplates\n    ): array {\n        $allParamsUnconstrained = true;\n        if (\\count($types) > 0) {\n            foreach ($types as $tNode) {\n                if (! self::isUnconstrainedType($tNode)) {\n                    $allParamsUnconstrained = false;\n\n                    break;\n                }\n            }\n        }\n\n        $returnUnconstrained = false;\n        if ($returnType instanceof IdentifierTypeNode) {\n            $lower = strtolower($returnType->name);\n            $returnUnconstrained = ($lower === 'mixed' || $lower === 'array');\n        }\n\n        $isSimple = ! $paramsUseGenerics\n            && ! $returnUsesGenerics\n            && \\count($aliases) === 0\n            && \\count($methodTemplates) === 0;\n\n        return [\n            'allParamsUnconstrained' => $allParamsUnconstrained,\n            'returnUnconstrained' => $returnUnconstrained,\n            'isSimple' => $isSimple,\n        ];\n    }\n\n    /**\n     * Parses PHPDoc contracts for a function or class method.\n     *\n     * @return FunctionContract\n     */\n    public static function parse(string $function): array\n    {\n        if (isset(self::$cache[$function])) {\n            return self::$cache[$function];\n        }\n\n        try {\n            if (str_contains($function, '::')) {\n                [$className, $methodName] = explode('::', $function, 2);\n\n                if (class_exists($className, false) || class_exists($className) || interface_exists($className) || trait_exists($className) || enum_exists($className)) {\n                    /** @var class-string<object> $className */\n                    $refClass = new \\ReflectionClass($className);\n                    if ($refClass->hasMethod($methodName)) {\n                        $ref = $refClass->getMethod($methodName);\n                        $contract = self::parseMethod($ref);\n                    } else {\n                        $classTemplates = [];\n                        $aliases = [];\n                        self::parseClassLevelDocs($refClass, $classTemplates, $aliases);\n                        $contract = [\n                            'types' => [],\n                            'paramOuts' => [],\n                            'selfOut' => null,\n                            'templates' => [],\n                            'classTemplates' => $classTemplates,\n                            'return' => null,\n                            'aliases' => $aliases,\n                            'sensitiveParams' => [],\n                            'hasParamContract' => false,\n                            'hasParamOutContract' => false,\n                            'hasSelfOutContract' => false,\n                            'hasReturnContract' => false,\n                            'paramsUseGenerics' => false,\n                            'returnUsesGenerics' => false,\n                            'returnUsesMethodTemplates' => false,\n                            'returnIsThis' => false,\n                            'returnIsDynamic' => false,\n                            'allParamsUnconstrained' => true,\n                            'returnUnconstrained' => false,\n                            'isSimple' => true,\n                        ];\n                    }\n                } else {\n                    $contract = [\n                        'types' => [],\n                        'paramOuts' => [],\n                        'selfOut' => null,\n                        'templates' => [],\n                        'classTemplates' => [],\n                        'return' => null,\n                        'aliases' => [],\n                        'sensitiveParams' => [],\n                        'hasParamContract' => false,\n                        'hasParamOutContract' => false,\n                        'hasSelfOutContract' => false,\n                        'hasReturnContract' => false,\n                        'paramsUseGenerics' => false,\n                        'returnUsesGenerics' => false,\n                        'returnUsesMethodTemplates' => false,\n                        'returnIsThis' => false,\n                        'returnIsDynamic' => false,\n                        'allParamsUnconstrained' => true,\n                        'returnUnconstrained' => false,\n                        'isSimple' => true,\n                    ];\n                }\n            } else {\n                $ref = new \\ReflectionFunction($function);\n                $contract = self::parseFunction($ref);\n            }\n        } catch (\\ReflectionException $e) {\n            $contract = [\n                'types' => [],\n                'paramOuts' => [],\n                'selfOut' => null,\n                'templates' => [],\n                'classTemplates' => [],\n                'return' => null,\n                'aliases' => [],\n                'sensitiveParams' => [],\n                'hasParamContract' => false,\n                'hasParamOutContract' => false,\n                'hasSelfOutContract' => false,\n                'hasReturnContract' => false,\n                'paramsUseGenerics' => false,\n                'returnUsesGenerics' => false,\n                'returnUsesMethodTemplates' => false,\n                'returnIsThis' => false,\n                'returnIsDynamic' => false,\n                'allParamsUnconstrained' => true,\n                'returnUnconstrained' => false,\n                'isSimple' => true,\n            ];\n        }\n\n        return self::$cache[$function] = $contract;\n    }\n\n    /**\n     * Parses and resolves the @var or @property docblock for a given class property with zero-allocation 2D caching.\n     */\n    public static function parseProperty(string $className, string $propertyName): ?TypeNode\n    {\n        if (isset(self::$propertyCache[$className][$propertyName]) || \\array_key_exists($propertyName, self::$propertyCache[$className] ?? [])) {\n            return self::$propertyCache[$className][$propertyName];\n        }\n\n        if (! class_exists($className, false) && ! class_exists($className) && ! trait_exists($className, false) && ! trait_exists($className) && ! interface_exists($className, false) && ! interface_exists($className) && ! enum_exists($className, false) && ! enum_exists($className)) {\n            return self::$propertyCache[$className][$propertyName] = null;\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $refClass = new \\ReflectionClass($className);\n\n            $resolved = self::findDeclaredPropertyDoc($refClass, $propertyName);\n            $doc = $resolved['doc'] ?? false;\n            $declaringClass = $resolved['declaringClass'] ?? null;\n            $typeNode = null;\n            $isMagicProperty = false;\n\n            if ($doc === false && Config::isMagicPropertiesEnabled()) {\n                $magicResolved = self::findMagicPropertyDoc($refClass, $propertyName);\n                if ($magicResolved !== null) {\n                    $doc = $magicResolved['doc'];\n                    $declaringClass = $magicResolved['declaringClass'];\n                    $typeNode = $magicResolved['typeNode'];\n                    $isMagicProperty = true;\n                }\n            }\n\n            if ($doc === false || $declaringClass === null || self::shouldIgnoreDoc($doc)) {\n                return self::$propertyCache[$className][$propertyName] = null;\n            }\n\n            if (! $isMagicProperty) {\n                $phpDocNode = DocblockExtractor::parseDocString($doc);\n                $varTags = DocblockExtractor::getVarTags($phpDocNode);\n\n                if (\\count($varTags) === 0) {\n                    return self::$propertyCache[$className][$propertyName] = null;\n                }\n\n                $typeNode = $varTags[0]->type;\n            }\n\n            if ($typeNode === null) {\n                return self::$propertyCache[$className][$propertyName] = null;\n            }\n\n            $aliases = [];\n            $classTemplates = [];\n            self::parseClassLevelDocs($declaringClass, $classTemplates, $aliases);\n\n            if (! $isMagicProperty) {\n                $phpDocNode = DocblockExtractor::parseDocString($doc);\n                DocblockExtractor::extractAliases($phpDocNode, $aliases, $declaringClass);\n            }\n\n            $typeNode = self::substituteAliases($typeNode, $aliases);\n            $resolvedNode = SpecialTypeResolver::resolve($typeNode, $declaringClass);\n\n            return self::$propertyCache[$className][$propertyName] = $resolvedNode;\n        } catch (\\Throwable $e) {\n            return self::$propertyCache[$className][$propertyName] = null;\n        }\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $refClass\n     *\n     * @return array{doc: string, declaringClass: \\ReflectionClass<object>}|null\n     */\n    private static function findDeclaredPropertyDoc(\\ReflectionClass $refClass, string $propertyName): ?array\n    {\n        $current = $refClass;\n        while ($current !== false) {\n            $className = $current->getName();\n            $stubDoc = StubManager::getPropertyDoc($className, $propertyName);\n            if ($stubDoc !== null) {\n                return ['doc' => $stubDoc, 'declaringClass' => $current];\n            }\n\n            foreach ($current->getTraits() as $trait) {\n                if ($trait->hasProperty($propertyName)) {\n                    $traitProp = $trait->getProperty($propertyName);\n                    $doc = $traitProp->getDocComment();\n                    if ($doc !== false) {\n                        return ['doc' => $doc, 'declaringClass' => $trait];\n                    }\n                }\n            }\n\n            if ($current->hasProperty($propertyName)) {\n                $refProp = $current->getProperty($propertyName);\n                $doc = $refProp->getDocComment();\n                if ($doc !== false) {\n                    return ['doc' => $doc, 'declaringClass' => $current];\n                }\n            }\n            $parent = $current->getParentClass();\n            $current = $parent !== false ? $parent : false;\n        }\n\n        foreach ($refClass->getInterfaces() as $interface) {\n            $interfaceName = $interface->getName();\n            $stubDoc = StubManager::getPropertyDoc($interfaceName, $propertyName);\n            if ($stubDoc !== null) {\n                return ['doc' => $stubDoc, 'declaringClass' => $interface];\n            }\n\n            if ($interface->hasProperty($propertyName)) {\n                $interfaceProp = $interface->getProperty($propertyName);\n                $doc = $interfaceProp->getDocComment();\n                if ($doc !== false) {\n                    return ['doc' => $doc, 'declaringClass' => $interface];\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $refClass\n     *\n     * @return array{doc: string, declaringClass: \\ReflectionClass<object>, typeNode: TypeNode}|null\n     */\n    private static function findMagicPropertyDoc(\\ReflectionClass $refClass, string $propertyName): ?array\n    {\n        $classHierarchy = HierarchyResolver::getClassHierarchy($refClass);\n\n        foreach ($classHierarchy as $hierClass) {\n            $className = $hierClass->getName();\n            $fileName = $hierClass->getFileName();\n            $stubDoc = StubManager::getClassDoc($className);\n\n            if ($stubDoc === null && $hierClass !== $refClass && FileFilter::isFileExcluded($fileName !== false ? $fileName : null)) {\n                continue;\n            }\n\n            $classDoc = $stubDoc ?? $hierClass->getDocComment();\n            if ($classDoc !== false && $classDoc !== null) {\n                $extractedType = DocblockExtractor::extractTypeFromClassPropertyDoc($classDoc, $propertyName);\n                if ($extractedType !== null) {\n                    return [\n                        'doc' => $classDoc,\n                        'declaringClass' => $hierClass,\n                        'typeNode' => $extractedType,\n                    ];\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Parses and resolves a class-level @method docblock for __call / __callStatic with zero-allocation 2D caching.\n     *\n     * @return array{return: ?TypeNode, parameters: array<int, array{name: string, type: ?TypeNode, isVariadic: bool, isOptional: bool}>, aliases: array<string, TypeNode>, templates: array<string, TemplateTagValueNode>}|null\n     */\n    public static function parseMagicMethod(string $className, string $methodName): ?array\n    {\n        if (isset(self::$magicMethodCache[$className][$methodName]) || \\array_key_exists($methodName, self::$magicMethodCache[$className] ?? [])) {\n            return self::$magicMethodCache[$className][$methodName];\n        }\n\n        if (! class_exists($className, false) && ! class_exists($className) && ! trait_exists($className, false) && ! trait_exists($className) && ! interface_exists($className, false) && ! interface_exists($className) && ! enum_exists($className, false) && ! enum_exists($className)) {\n            return self::$magicMethodCache[$className][$methodName] = null;\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $refClass = new \\ReflectionClass($className);\n\n            $resolved = self::findMagicMethodDoc($refClass, $methodName);\n            if ($resolved === null) {\n                return self::$magicMethodCache[$className][$methodName] = null;\n            }\n\n            $doc = $resolved['doc'];\n            $declaringClass = $resolved['declaringClass'];\n            $methodTag = $resolved['methodTag'];\n\n            if (self::shouldIgnoreDoc($doc)) {\n                return self::$magicMethodCache[$className][$methodName] = null;\n            }\n\n            $aliases = [];\n            $classTemplates = [];\n            self::parseClassLevelDocs($declaringClass, $classTemplates, $aliases);\n\n            $phpDocNode = DocblockExtractor::parseDocString($doc);\n            DocblockExtractor::extractAliases($phpDocNode, $aliases, $declaringClass);\n\n            $resolvedReturn = null;\n            if ($methodTag->returnType !== null) {\n                $subReturn = self::substituteAliases($methodTag->returnType, $aliases);\n                $resolvedReturn = SpecialTypeResolver::resolve($subReturn, $declaringClass);\n            }\n\n            $resolvedParams = self::resolveMagicParameters($methodTag, $declaringClass, $aliases);\n\n            return self::$magicMethodCache[$className][$methodName] = [\n                'return' => $resolvedReturn,\n                'parameters' => $resolvedParams,\n                'aliases' => $aliases,\n                'templates' => $classTemplates,\n            ];\n        } catch (\\Throwable $e) {\n            return self::$magicMethodCache[$className][$methodName] = null;\n        }\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $refClass\n     *\n     * @return array{doc: string, declaringClass: \\ReflectionClass<object>, methodTag: MethodTagValueNode}|null\n     */\n    private static function findMagicMethodDoc(\\ReflectionClass $refClass, string $methodName): ?array\n    {\n        $classHierarchy = HierarchyResolver::getClassHierarchy($refClass);\n\n        foreach ($classHierarchy as $hierClass) {\n            $className = $hierClass->getName();\n            $fileName = $hierClass->getFileName();\n            $stubDoc = StubManager::getClassDoc($className);\n\n            if ($stubDoc === null && $hierClass !== $refClass && FileFilter::isFileExcluded($fileName !== false ? $fileName : null)) {\n                continue;\n            }\n\n            $classDoc = $stubDoc ?? $hierClass->getDocComment();\n            if ($classDoc !== false && $classDoc !== null) {\n                $tag = DocblockExtractor::extractMagicMethodContract($classDoc, $methodName);\n                if ($tag !== null) {\n                    return [\n                        'doc' => $classDoc,\n                        'declaringClass' => $hierClass,\n                        'methodTag' => $tag,\n                    ];\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $declaringClass\n     * @param array<string, TypeNode> $aliases\n     *\n     * @return array<int, array{name: string, type: ?TypeNode, isVariadic: bool, isOptional: bool}>\n     */\n    private static function resolveMagicParameters(\n        MethodTagValueNode $methodTag,\n        \\ReflectionClass $declaringClass,\n        array $aliases\n    ): array {\n        $resolvedParams = [];\n\n        foreach ($methodTag->parameters as $p) {\n            $pType = $p->type ?? null;\n            if ($pType !== null) {\n                $subType = self::substituteAliases($pType, $aliases);\n                $pType = SpecialTypeResolver::resolve($subType, $declaringClass);\n            }\n\n            $pName = self::extractRawParamName($p);\n            $pVars = get_object_vars($p);\n            $isOptional = (isset($pVars['isOptional']) && (bool) $pVars['isOptional']) || (($p->defaultValue ?? null) !== null);\n\n            $resolvedParams[] = [\n                'name' => $pName,\n                'type' => $pType,\n                'isVariadic' => $p->isVariadic,\n                'isOptional' => $isOptional,\n            ];\n        }\n\n        return $resolvedParams;\n    }\n\n    private static function extractRawParamName(object $paramNode): string\n    {\n        $rawParamName = '';\n        $pVars = get_object_vars($paramNode);\n\n        foreach ($pVars as $key => $val) {\n            if (\\is_string($val) && str_starts_with($val, '$')) {\n                $rawParamName = $val;\n\n                break;\n            }\n        }\n\n        if ($rawParamName === '') {\n            foreach (['parameterName', 'name', 'paramName', 'varName'] as $key) {\n                if (isset($pVars[$key]) && \\is_string($pVars[$key])) {\n                    $rawParamName = $pVars[$key];\n\n                    break;\n                }\n            }\n        }\n\n        return ltrim($rawParamName, '$');\n    }\n\n    private static function shouldIgnoreDoc(string $doc): bool\n    {\n        return Config::isRespectIgnoreTagsEnabled() && \\TypePHP\\Internal\\Util\\IgnoreManager::hasIgnoreDocTag($doc);\n    }\n\n    private static function hasSensitiveAttribute(\\ReflectionParameter $param): bool\n    {\n        foreach ($param->getAttributes() as $attr) {\n            $name = ltrim($attr->getName(), '\\\\');\n            if ($name === 'SensitiveParameter' || str_ends_with($name, '\\\\SensitiveParameter')) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Extracts and returns all class-level type aliases for a given class.\n     *\n     * @return array<string, TypeNode>\n     */\n    public static function parseClassAliases(string $className): array\n    {\n        if (isset(self::$classLevelDocCache[$className])) {\n            return self::$classLevelDocCache[$className]['aliases'];\n        }\n\n        if (! class_exists($className, false) && ! class_exists($className) && ! interface_exists($className, false) && ! interface_exists($className) && ! trait_exists($className, false) && ! trait_exists($className) && ! enum_exists($className, false) && ! enum_exists($className)) {\n            return [];\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $refClass = new \\ReflectionClass($className);\n            $aliases = [];\n            $classTemplates = [];\n            self::parseClassLevelDocs($refClass, $classTemplates, $aliases);\n\n            return $aliases;\n        } catch (\\Throwable $e) {\n            return [];\n        }\n    }\n\n    /**\n     * Orchestrates parsing for class methods across the inheritance hierarchy.\n     *\n     * @return FunctionContract\n     */\n    private static function parseMethod(\\ReflectionMethod $ref): array\n    {\n        /** @var array<string, TypeNode> $types */\n        $types = [];\n        /** @var array<string, TypeNode> $paramOuts */\n        $paramOuts = [];\n        /** @var array<string, TemplateTagValueNode> $methodTemplates */\n        $methodTemplates = [];\n        /** @var array<string, TemplateTagValueNode> $classTemplates */\n        $classTemplates = [];\n        $returnType = null;\n        $selfOut = null;\n        /** @var array<string, TypeNode> $aliases */\n        $aliases = [];\n        /** @var array<string, bool> $sensitiveParams */\n        $sensitiveParams = [];\n\n        $targetClass = (class_exists($ref->class, false) || class_exists($ref->class) || interface_exists($ref->class) || enum_exists($ref->class) || trait_exists($ref->class))\n            ? new \\ReflectionClass($ref->class)\n            : $ref->getDeclaringClass();\n\n        self::parseClassLevelDocs($targetClass, $classTemplates, $aliases);\n        if ($targetClass->getName() !== $ref->getDeclaringClass()->getName()) {\n            self::parseClassLevelDocs($ref->getDeclaringClass(), $classTemplates, $aliases);\n        }\n\n        self::parseMethodHierarchyDocs($ref, $types, $methodTemplates, $returnType, $aliases, $paramOuts, $selfOut, $classTemplates, $sensitiveParams);\n\n        if ($ref->getName() === '__construct') {\n            self::applyConstructorPromotionFallback($ref, $types, $classTemplates, $aliases);\n        }\n\n        $allTemplates = [...$classTemplates, ...$methodTemplates];\n        $paramsUseGenerics = false;\n        if (\\count($allTemplates) > 0) {\n            foreach ($types as $tNode) {\n                if (self::typeReferencesTemplate($tNode, $allTemplates)) {\n                    $paramsUseGenerics = true;\n\n                    break;\n                }\n            }\n            if (! $paramsUseGenerics) {\n                foreach ($paramOuts as $tNode) {\n                    if (self::typeReferencesTemplate($tNode, $allTemplates)) {\n                        $paramsUseGenerics = true;\n\n                        break;\n                    }\n                }\n            }\n            if (! $paramsUseGenerics && $selfOut !== null) {\n                if (self::typeReferencesTemplate($selfOut, $allTemplates)) {\n                    $paramsUseGenerics = true;\n                }\n            }\n        }\n\n        $returnUsesMethodTemplates = false;\n        if ($returnType !== null && \\count($methodTemplates) > 0) {\n            $returnUsesMethodTemplates = self::typeReferencesTemplate($returnType, $methodTemplates);\n        }\n\n        $returnUsesGenerics = $returnUsesMethodTemplates;\n        if (! $returnUsesGenerics && $returnType !== null && \\count($classTemplates) > 0) {\n            $returnUsesGenerics = self::typeReferencesTemplate($returnType, $classTemplates);\n        }\n\n        $returnIsThis = false;\n        $returnIsDynamic = false;\n        if ($returnType !== null) {\n            $retStr = (string) $returnType;\n            $returnIsThis = ($returnType instanceof \\PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode)\n                || ($returnType instanceof IdentifierTypeNode && strtolower($returnType->name) === '$this');\n            $returnIsDynamic = $returnIsThis || str_contains($retStr, 'static') || str_contains($retStr, '$this');\n        }\n\n        $flags = self::computeContractFlags(\n            $types,\n            $returnType,\n            $paramsUseGenerics,\n            $returnUsesGenerics,\n            $aliases,\n            $methodTemplates\n        );\n\n        return [\n            'types' => $types,\n            'paramOuts' => $paramOuts,\n            'selfOut' => $selfOut,\n            'templates' => $methodTemplates,\n            'classTemplates' => $classTemplates,\n            'allTemplates' => $allTemplates,\n            'return' => $returnType,\n            'aliases' => $aliases,\n            'sensitiveParams' => $sensitiveParams,\n            'hasParamContract' => \\count($types) > 0,\n            'hasParamOutContract' => \\count($paramOuts) > 0,\n            'hasSelfOutContract' => $selfOut !== null,\n            'hasReturnContract' => $returnType !== null,\n            'paramsUseGenerics' => $paramsUseGenerics,\n            'returnUsesGenerics' => $returnUsesGenerics,\n            'returnUsesMethodTemplates' => $returnUsesMethodTemplates,\n            'returnIsThis' => $returnIsThis,\n            'returnIsDynamic' => $returnIsDynamic,\n            'allParamsUnconstrained' => $flags['allParamsUnconstrained'],\n            'returnUnconstrained' => $flags['returnUnconstrained'],\n            'isSimple' => $flags['isSimple'],\n        ];\n    }\n\n    /**\n     * Orchestrates parsing for standalone global or namespaced functions.\n     *\n     * @return FunctionContract\n     */\n    private static function parseFunction(\\ReflectionFunction $ref): array\n    {\n        $types = [];\n        $paramOuts = [];\n        $templates = [];\n        $returnType = null;\n        $aliases = [];\n        $sensitiveParams = [];\n\n        $funcName = $ref->getName();\n        $stubDoc = StubManager::getFunctionDoc($funcName);\n        $doc = $stubDoc ?? $ref->getDocComment();\n\n        $baseParams = $ref->getParameters();\n        $baseParamVariadic = [];\n        $baseParamObjects = [];\n        foreach ($baseParams as $p) {\n            $baseParamVariadic[$p->getName()] = $p->isVariadic();\n            $baseParamObjects[$p->getName()] = $p;\n            if (self::hasSensitiveAttribute($p)) {\n                $sensitiveParams[$p->getName()] = true;\n            }\n        }\n\n        if ($doc === false || $doc === null || self::shouldIgnoreDoc($doc)) {\n            return [\n                'types' => [],\n                'paramOuts' => [],\n                'selfOut' => null,\n                'templates' => [],\n                'classTemplates' => [],\n                'allTemplates' => $templates,\n                'return' => null,\n                'aliases' => [],\n                'sensitiveParams' => $sensitiveParams,\n                'hasParamContract' => false,\n                'hasParamOutContract' => false,\n                'hasSelfOutContract' => false,\n                'hasReturnContract' => false,\n                'paramsUseGenerics' => false,\n                'returnUsesGenerics' => false,\n                'returnUsesMethodTemplates' => false,\n                'returnIsThis' => false,\n                'returnIsDynamic' => false,\n                'allParamsUnconstrained' => true,\n                'returnUnconstrained' => false,\n                'isSimple' => true,\n            ];\n        }\n\n        $phpDocNode = DocblockExtractor::parseDocString($doc);\n\n        foreach (DocblockExtractor::extractTemplates($phpDocNode) as $name => $tag) {\n            $templates[$name] = $tag;\n        }\n        DocblockExtractor::extractAliases($phpDocNode, $aliases, $ref);\n\n        foreach (DocblockExtractor::getParamTags($phpDocNode) as $paramName => $paramTag) {\n            $type = $paramTag->type;\n            $pObj = $baseParamObjects[$paramName] ?? null;\n\n            $type = self::wrapVariadicParameterType($type, $paramTag->isVariadic, $baseParamVariadic[$paramName] ?? false, $pObj);\n\n            if (\n                Config::isRespectNativeNullabilityEnabled()\n                && $pObj !== null\n                && self::parameterExplicitlyAllowsNull($pObj)\n                && ! self::typeContainsNull($type)\n            ) {\n                $type = new NullableTypeNode($type);\n            }\n\n            $substitutedType = self::substituteAliases($type, $aliases);\n            $resolvedType = SpecialTypeResolver::resolve($substitutedType, $ref);\n\n            if ($resolvedType instanceof IdentifierTypeNode && strtolower($resolvedType->name) === 'mixed') {\n                continue;\n            }\n\n            $types[$paramName] = $resolvedType;\n        }\n\n        foreach (DocblockExtractor::getParamOutTags($phpDocNode) as $paramName => $paramOutTag) {\n            $type = $paramOutTag->type;\n            $substitutedType = self::substituteAliases($type, $aliases);\n            $resolvedType = SpecialTypeResolver::resolve($substitutedType, $ref);\n            $paramOuts[$paramName] = $resolvedType;\n        }\n\n        $returnTag = DocblockExtractor::getReturnTag($phpDocNode);\n        if ($returnTag !== null) {\n            $substitutedReturn = self::substituteAliases($returnTag->type, $aliases);\n            $returnType = SpecialTypeResolver::resolve($substitutedReturn, $ref);\n\n            if (\n                Config::isRespectNativeNullabilityEnabled()\n                && self::returnTypeExplicitlyAllowsNull($ref)\n                && ! self::typeContainsNull($returnType)\n            ) {\n                $returnType = new NullableTypeNode($returnType);\n            }\n        }\n\n        $paramsUseGenerics = false;\n        if (\\count($templates) > 0) {\n            foreach ($types as $tNode) {\n                if (self::typeReferencesTemplate($tNode, $templates)) {\n                    $paramsUseGenerics = true;\n\n                    break;\n                }\n            }\n            if (! $paramsUseGenerics) {\n                foreach ($paramOuts as $tNode) {\n                    if (self::typeReferencesTemplate($tNode, $templates)) {\n                        $paramsUseGenerics = true;\n\n                        break;\n                    }\n                }\n            }\n        }\n\n        $returnUsesMethodTemplates = false;\n        if ($returnType !== null && \\count($templates) > 0) {\n            $returnUsesMethodTemplates = self::typeReferencesTemplate($returnType, $templates);\n        }\n\n        $returnIsThis = false;\n        $returnIsDynamic = false;\n        if ($returnType !== null) {\n            $retStr = (string) $returnType;\n            $returnIsThis = ($returnType instanceof \\PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode)\n                || ($returnType instanceof IdentifierTypeNode && strtolower($returnType->name) === '$this');\n            $returnIsDynamic = $returnIsThis || str_contains($retStr, 'static') || str_contains($retStr, '$this');\n        }\n\n        $flags = self::computeContractFlags(\n            $types,\n            $returnType,\n            $paramsUseGenerics,\n            $returnUsesMethodTemplates,\n            $aliases,\n            $templates\n        );\n\n        return [\n            'types' => $types,\n            'paramOuts' => $paramOuts,\n            'selfOut' => null,\n            'templates' => $templates,\n            'classTemplates' => [],\n            'allTemplates' => $templates,\n            'return' => $returnType,\n            'aliases' => $aliases,\n            'sensitiveParams' => $sensitiveParams,\n            'hasParamContract' => \\count($types) > 0,\n            'hasParamOutContract' => \\count($paramOuts) > 0,\n            'hasSelfOutContract' => false,\n            'hasReturnContract' => $returnType !== null,\n            'paramsUseGenerics' => $paramsUseGenerics,\n            'returnUsesGenerics' => $returnUsesMethodTemplates,\n            'returnUsesMethodTemplates' => $returnUsesMethodTemplates,\n            'returnIsThis' => $returnIsThis,\n            'returnIsDynamic' => $returnIsDynamic,\n            'allParamsUnconstrained' => $flags['allParamsUnconstrained'],\n            'returnUnconstrained' => $flags['returnUnconstrained'],\n            'isSimple' => $flags['isSimple'],\n        ];\n    }\n\n    /**\n     * Resolves class-level docblocks (templates and aliases) up the class inheritance chain.\n     *\n     * @param \\ReflectionClass<object> $declaringClass\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param array<string, TypeNode> $aliases\n     */\n    private static function parseClassLevelDocs(\\ReflectionClass $declaringClass, array &$templates, array &$aliases): void\n    {\n        $className = $declaringClass->getName();\n        if (isset(self::$classLevelDocCache[$className])) {\n            $cached = self::$classLevelDocCache[$className];\n            foreach ($cached['templates'] as $name => $tag) {\n                if (! isset($templates[$name])) {\n                    $templates[$name] = $tag;\n                }\n            }\n            foreach ($cached['aliases'] as $name => $alias) {\n                if (! isset($aliases[$name])) {\n                    $aliases[$name] = $alias;\n                }\n            }\n\n            return;\n        }\n\n        $classHierarchy = HierarchyResolver::getClassHierarchy($declaringClass);\n        /** @var array<string, TemplateTagValueNode> $localTemplates */\n        $localTemplates = [];\n        /** @var array<string, TypeNode> $localAliases */\n        $localAliases = [];\n\n        foreach ($classHierarchy as $hierClass) {\n            $hierClassName = $hierClass->getName();\n            $fileName = $hierClass->getFileName();\n            $stubDoc = StubManager::getClassDoc($hierClassName);\n\n            if ($stubDoc === null && FileFilter::isFileExcluded($fileName !== false ? $fileName : null)) {\n                continue;\n            }\n\n            $classDoc = $stubDoc ?? $hierClass->getDocComment();\n            if ($classDoc !== false && $classDoc !== null) {\n                $classPhpDocNode = DocblockExtractor::parseDocString($classDoc);\n\n                foreach (DocblockExtractor::extractTemplates($classPhpDocNode) as $name => $tag) {\n                    if (! isset($localTemplates[$name])) {\n                        if ($tag->bound !== null || $tag->default !== null) {\n                            $tag = new TemplateTagValueNode(\n                                $tag->name,\n                                $tag->bound !== null ? SpecialTypeResolver::resolve($tag->bound, $hierClass) : null,\n                                $tag->description,\n                                $tag->default !== null ? SpecialTypeResolver::resolve($tag->default, $hierClass) : null\n                            );\n                        }\n                        $localTemplates[$name] = $tag;\n                    }\n                }\n                DocblockExtractor::extractAliases($classPhpDocNode, $localAliases, $hierClass);\n            }\n        }\n\n        self::$classLevelDocCache[$className] = [\n            'templates' => $localTemplates,\n            'aliases' => $localAliases,\n        ];\n\n        foreach ($localTemplates as $name => $tag) {\n            if (! isset($templates[$name])) {\n                $templates[$name] = $tag;\n            }\n        }\n        foreach ($localAliases as $name => $alias) {\n            if (! isset($aliases[$name])) {\n                $aliases[$name] = $alias;\n            }\n        }\n    }\n\n    /**\n     * Resolves method-level docblocks (@param, @param-out, @return, @template, aliases) up the method hierarchy.\n     *\n     * @param \\ReflectionMethod $ref\n     * @param array<string, TypeNode> $types\n     * @param array<string, TemplateTagValueNode> $templates\n     * @param TypeNode|null $returnType\n     * @param array<string, TypeNode> $aliases\n     * @param array<string, TypeNode> $paramOuts\n     * @param TypeNode|null $selfOut\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     * @param array<string, bool> $sensitiveParams\n     */\n    private static function parseMethodHierarchyDocs(\n        \\ReflectionMethod $ref,\n        array &$types,\n        array &$templates,\n        ?TypeNode &$returnType,\n        array &$aliases,\n        array &$paramOuts = [],\n        ?TypeNode &$selfOut = null,\n        array &$classTemplates = [],\n        array &$sensitiveParams = []\n    ): void {\n        $hierarchy = HierarchyResolver::getMethodHierarchy($ref);\n        $baseParams = $ref->getParameters();\n        $baseParamNames = [];\n        $baseParamSet = [];\n        $baseParamVariadic = [];\n        $baseParamObjects = [];\n        $isConstructor = ($ref->getName() === '__construct');\n\n        foreach ($baseParams as $idx => $p) {\n            $baseParamNames[$idx] = $p->getName();\n            $baseParamSet[$p->getName()] = $idx;\n            $baseParamVariadic[$p->getName()] = $p->isVariadic();\n            $baseParamObjects[$p->getName()] = $p;\n            if (self::hasSensitiveAttribute($p)) {\n                $sensitiveParams[$p->getName()] = true;\n            }\n        }\n\n        foreach ($hierarchy as $hierRef) {\n            $hierDeclaringClass = $hierRef->getDeclaringClass();\n            self::parseClassLevelDocs($hierDeclaringClass, $classTemplates, $aliases);\n\n            $isOriginal = ($hierRef === $ref);\n            $declaringClass = $hierDeclaringClass->getName();\n            $methodName = $hierRef->getName();\n            $stubDoc = StubManager::getMethodDoc($declaringClass, $methodName);\n\n            $fileName = $hierRef->getFileName();\n            if ($stubDoc === null && ! $isOriginal && FileFilter::isFileExcluded($fileName !== false ? $fileName : null)) {\n                continue;\n            }\n\n            $hierParams = $hierRef->getParameters();\n            $hierNameToIndex = [];\n            foreach ($hierParams as $idx => $p) {\n                $hierNameToIndex[$p->getName()] = $idx;\n                if (self::hasSensitiveAttribute($p)) {\n                    $targetName = self::resolveTargetParamName(\n                        $p->getName(),\n                        $baseParamSet,\n                        $baseParamNames,\n                        $hierNameToIndex,\n                        $isConstructor\n                    );\n                    $sensitiveParams[$targetName ?? $p->getName()] = true;\n                }\n            }\n\n            $doc = $stubDoc ?? $hierRef->getDocComment();\n            if ($doc === false || $doc === null || self::shouldIgnoreDoc($doc)) {\n                continue;\n            }\n\n            $phpDocNode = DocblockExtractor::parseDocString($doc);\n\n            foreach (DocblockExtractor::extractTemplates($phpDocNode) as $name => $tag) {\n                if (! isset($templates[$name])) {\n                    $templates[$name] = $tag;\n                }\n            }\n            DocblockExtractor::extractAliases($phpDocNode, $aliases, $hierRef);\n\n            $paramTags = DocblockExtractor::getParamTags($phpDocNode);\n\n            foreach ($paramTags as $paramName => $paramTag) {\n                $targetParamName = self::resolveTargetParamName(\n                    $paramName,\n                    $baseParamSet,\n                    $baseParamNames,\n                    $hierNameToIndex,\n                    $isConstructor\n                );\n\n                if ($targetParamName !== null && ! isset($types[$targetParamName])) {\n                    $type = $paramTag->type;\n                    $pObj = $baseParamObjects[$targetParamName] ?? null;\n\n                    $type = self::wrapVariadicParameterType($type, $paramTag->isVariadic, $baseParamVariadic[$targetParamName] ?? false, $pObj);\n\n                    if (\n                        Config::isRespectNativeNullabilityEnabled()\n                        && $pObj !== null\n                        && self::parameterExplicitlyAllowsNull($pObj)\n                        && ! self::typeContainsNull($type)\n                    ) {\n                        $type = new NullableTypeNode($type);\n                    }\n\n                    $substitutedType = self::substituteAliases($type, $aliases);\n                    $resolvedType = SpecialTypeResolver::resolve($substitutedType, $hierRef);\n\n                    if ($resolvedType instanceof IdentifierTypeNode && strtolower($resolvedType->name) === 'mixed') {\n                        continue;\n                    }\n\n                    $types[$targetParamName] = $resolvedType;\n                }\n            }\n\n            $paramOutTags = DocblockExtractor::getParamOutTags($phpDocNode);\n            foreach ($paramOutTags as $paramName => $paramOutTag) {\n                $targetParamName = self::resolveTargetParamName(\n                    $paramName,\n                    $baseParamSet,\n                    $baseParamNames,\n                    $hierNameToIndex,\n                    $isConstructor\n                );\n\n                if ($targetParamName !== null && ! isset($paramOuts[$targetParamName])) {\n                    $type = $paramOutTag->type;\n                    $substitutedType = self::substituteAliases($type, $aliases);\n                    $resolvedType = SpecialTypeResolver::resolve($substitutedType, $hierRef);\n                    $paramOuts[$targetParamName] = $resolvedType;\n                }\n            }\n\n            $selfOutType = DocblockExtractor::getSelfOutTag($phpDocNode);\n            if ($selfOutType !== null && $selfOut === null) {\n                $substituted = self::substituteAliases($selfOutType, $aliases);\n                $selfOut = SpecialTypeResolver::resolve($substituted, $hierRef);\n            }\n\n            if ($returnType === null) {\n                $returnTag = DocblockExtractor::getReturnTag($phpDocNode);\n                if ($returnTag !== null) {\n                    $substitutedReturn = self::substituteAliases($returnTag->type, $aliases);\n                    $returnType = SpecialTypeResolver::resolve($substitutedReturn, $hierRef);\n\n                    if (\n                        Config::isRespectNativeNullabilityEnabled()\n                        && self::returnTypeExplicitlyAllowsNull($ref)\n                        && ! self::typeContainsNull($returnType)\n                    ) {\n                        $returnType = new NullableTypeNode($returnType);\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Disambiguates parameter name vs index position during inheritance.\n     *\n     * @param array<string, int> $baseParamSet\n     * @param array<int, string> $baseParamNames\n     * @param array<string, int> $hierNameToIndex\n     */\n    private static function resolveTargetParamName(\n        string $paramName,\n        array $baseParamSet,\n        array $baseParamNames,\n        array $hierNameToIndex,\n        bool $isConstructor = false\n    ): ?string {\n        if (isset($baseParamSet[$paramName])) {\n            return $paramName;\n        }\n\n        if ($isConstructor) {\n            return null;\n        }\n\n        $paramIndex = $hierNameToIndex[$paramName] ?? null;\n        if ($paramIndex === null || ! isset($baseParamNames[$paramIndex])) {\n            return null;\n        }\n\n        $candidateName = $baseParamNames[$paramIndex];\n\n        return ! isset($hierNameToIndex[$candidateName]) ? $candidateName : null;\n    }\n\n    /**\n     * Falls back to property @var docblocks for constructor parameters if un-annotated,\n     * ensuring scalar constructor parameters are never overridden by conflicting object property types.\n     *\n     * @param \\ReflectionMethod $ref\n     * @param array<string, TypeNode> $types\n     * @param array<string, TemplateTagValueNode> $classTemplates\n     * @param array<string, TypeNode> $aliases\n     */\n    private static function applyConstructorPromotionFallback(\n        \\ReflectionMethod $ref,\n        array &$types,\n        array $classTemplates = [],\n        array $aliases = []\n    ): void {\n        $declaringClass = $ref->getDeclaringClass();\n\n        foreach ($ref->getParameters() as $p) {\n            $paramName = $p->getName();\n\n            if (! isset($types[$paramName]) && $declaringClass->hasProperty($paramName)) {\n                $propertyRef = $declaringClass->getProperty($paramName);\n\n                if (! self::areConstructorParamAndPropertyCompatible($p, $propertyRef)) {\n                    continue;\n                }\n\n                $className = $declaringClass->getName();\n                $stubDoc = StubManager::getPropertyDoc($className, $paramName);\n                $propDoc = $stubDoc ?? $propertyRef->getDocComment();\n\n                if ($propDoc !== false && $propDoc !== null) {\n                    $propType = DocblockExtractor::extractTypeFromPropertyDoc($propDoc, $paramName);\n                    if ($propType !== null) {\n                        $substitutedProp = self::substituteAliases($propType, $aliases);\n                        $resolvedProp = SpecialTypeResolver::resolve($substitutedProp, $ref);\n\n                        if ($p->hasType()) {\n                            $nativeType = $p->getType();\n                            if ($nativeType instanceof \\ReflectionNamedType) {\n                                $nativeName = strtolower($nativeType->getName());\n                                $propTypeStr = strtolower((string) $resolvedProp);\n\n                                if (\n                                    $nativeType->isBuiltin()\n                                    && ! \\in_array($nativeName, ['array', 'iterable', 'mixed'], true)\n                                    && ! \\in_array($propTypeStr, [$nativeName, 'mixed'], true)\n                                    && ! self::isRefinementOfBuiltin($propTypeStr, $nativeName)\n                                ) {\n                                    continue;\n                                }\n                            }\n                        }\n\n                        $resolvedProp = self::wrapVariadicParameterType($resolvedProp, false, $p->isVariadic(), $p);\n\n                        if (\n                            Config::isRespectNativeNullabilityEnabled()\n                            && self::parameterExplicitlyAllowsNull($p)\n                            && ! self::typeContainsNull($resolvedProp)\n                        ) {\n                            $resolvedProp = new NullableTypeNode($resolvedProp);\n                        }\n\n                        if ($resolvedProp instanceof IdentifierTypeNode && strtolower($resolvedProp->name) === 'mixed') {\n                            continue;\n                        }\n\n                        $types[$paramName] = $resolvedProp;\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Checks whether an un-promoted constructor parameter is compatible with a class property.\n     */\n    private static function areConstructorParamAndPropertyCompatible(\n        \\ReflectionParameter $p,\n        \\ReflectionProperty $propertyRef\n    ): bool {\n        if ($p->isPromoted()) {\n            return true;\n        }\n\n        if ($p->hasType() && $propertyRef->hasType()) {\n            $pType = (string) $p->getType();\n            $propType = (string) $propertyRef->getType();\n\n            $normP = strtolower(ltrim($pType, '?'));\n            $normProp = strtolower(ltrim($propType, '?'));\n\n            if ($normP !== $normProp) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Wraps a variadic parameter type into an ArrayTypeNode, accounting for variadic arrays/iterables.\n     */\n    private static function wrapVariadicParameterType(\n        TypeNode $type,\n        bool $tagIsVariadic,\n        bool $nativeIsVariadic,\n        ?\\ReflectionParameter $reflectionParam = null\n    ): TypeNode {\n        if (! $tagIsVariadic && ! $nativeIsVariadic) {\n            return $type;\n        }\n\n        $isNativeArrayOrIterable = false;\n        if ($reflectionParam !== null && $reflectionParam->hasType()) {\n            $nativeType = $reflectionParam->getType();\n            if ($nativeType instanceof \\ReflectionNamedType) {\n                $nativeName = strtolower($nativeType->getName());\n                $isNativeArrayOrIterable = \\in_array($nativeName, ['array', 'iterable'], true);\n            }\n        }\n\n        if ($isNativeArrayOrIterable) {\n            return new ArrayTypeNode($type);\n        }\n\n        if (\n            ! ($type instanceof ArrayTypeNode)\n            && ! ($type instanceof GenericTypeNode && \\in_array(strtolower($type->type->name), ['array', 'list', 'iterable', 'traversable', 'non-empty-array', 'non-empty-list'], true))\n        ) {\n            return new ArrayTypeNode($type);\n        }\n\n        return $type;\n    }\n\n    /**\n     * Checks if a scalar refinement type is compatible with a native PHP builtin type.\n     */\n    private static function isRefinementOfBuiltin(string $refinement, string $builtin): bool\n    {\n        if (isset(self::BUILTIN_REFINEMENTS[$builtin][$refinement])) {\n            return true;\n        }\n\n        if (($builtin === 'int' || $builtin === 'integer') && str_starts_with($refinement, 'int<')) {\n            return true;\n        }\n\n        if ($builtin === 'string' && str_starts_with($refinement, 'class-string<')) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if a reflection parameter explicitly declares a nullable native typehint or default null value (excluding mixed).\n     */\n    private static function parameterExplicitlyAllowsNull(\\ReflectionParameter $p): bool\n    {\n        if (! $p->hasType()) {\n            return $p->isDefaultValueAvailable() && $p->getDefaultValue() === null;\n        }\n\n        $type = $p->getType();\n        if ($type instanceof \\ReflectionNamedType) {\n            $name = strtolower($type->getName());\n            if ($name === 'mixed') {\n                return false;\n            }\n\n            return $type->allowsNull();\n        }\n\n        if ($type instanceof \\ReflectionUnionType) {\n            return $type->allowsNull();\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if a reflection function or method explicitly declares a nullable native return type (excluding void, mixed, and never).\n     */\n    private static function returnTypeExplicitlyAllowsNull(\\ReflectionFunctionAbstract $ref): bool\n    {\n        if (! $ref->hasReturnType()) {\n            return false;\n        }\n\n        $type = $ref->getReturnType();\n        if ($type instanceof \\ReflectionNamedType) {\n            $name = strtolower($type->getName());\n            if ($name === 'mixed' || $name === 'void' || $name === 'never') {\n                return false;\n            }\n\n            return $type->allowsNull();\n        }\n\n        if ($type instanceof \\ReflectionUnionType) {\n            return $type->allowsNull();\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if a TypeNode already represents or contains null.\n     */\n    private static function typeContainsNull(TypeNode $node): bool\n    {\n        if ($node instanceof NullableTypeNode) {\n            return true;\n        }\n\n        if ($node instanceof IdentifierTypeNode && (\\in_array(strtolower($node->name), ['null', 'mixed'], true))) {\n            return true;\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            foreach ($node->types as $t) {\n                if (self::typeContainsNull($t)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Recursively substitutes all type aliases inside a TypeNode AST and simplifies unions/intersections containing `mixed`.\n     *\n     * @param array<string, TypeNode> $aliases\n     */\n    public static function substituteAliases(TypeNode $node, array $aliases): TypeNode\n    {\n        if ($aliases === []) {\n            return $node;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            if (isset($aliases[$node->name])) {\n                return self::substituteAliases($aliases[$node->name], $aliases);\n            }\n\n            return $node;\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            $parameters = array_map(\n                fn (CallableTypeParameterNode $param) => new CallableTypeParameterNode(\n                    self::substituteAliases($param->type, $aliases),\n                    $param->isReference,\n                    $param->isVariadic,\n                    $param->parameterName,\n                    $param->isOptional\n                ),\n                $node->parameters\n            );\n\n            $returnType = self::substituteAliases($node->returnType, $aliases);\n\n            return new CallableTypeNode(\n                $node->identifier,\n                $parameters,\n                $returnType,\n                $node->templateTypes\n            );\n        }\n\n        if ($node instanceof OffsetAccessTypeNode) {\n            return new OffsetAccessTypeNode(\n                self::substituteAliases($node->type, $aliases),\n                self::substituteAliases($node->offset, $aliases)\n            );\n        }\n\n        if ($node instanceof ArrayTypeNode) {\n            return new ArrayTypeNode(self::substituteAliases($node->type, $aliases));\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            $genericType = self::substituteAliases($node->type, $aliases);\n            $genericTypes = array_map(\n                fn ($t) => self::substituteAliases($t, $aliases),\n                $node->genericTypes\n            );\n\n            return new GenericTypeNode(\n                $genericType instanceof IdentifierTypeNode ? $genericType : $node->type,\n                $genericTypes,\n                $node->variances\n            );\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return new NullableTypeNode(self::substituteAliases($node->type, $aliases));\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            $types = array_map(\n                fn ($t) => self::substituteAliases($t, $aliases),\n                $node->types\n            );\n\n            foreach ($types as $t) {\n                if ($t instanceof IdentifierTypeNode && strtolower($t->name) === 'mixed') {\n                    return new IdentifierTypeNode('mixed');\n                }\n            }\n\n            return new UnionTypeNode($types);\n        }\n\n        if ($node instanceof IntersectionTypeNode) {\n            $types = array_map(\n                fn ($t) => self::substituteAliases($t, $aliases),\n                $node->types\n            );\n\n            $filtered = array_values(array_filter($types, function ($t) {\n                return ! ($t instanceof IdentifierTypeNode && strtolower($t->name) === 'mixed');\n            }));\n\n            if (\\count($filtered) === 0) {\n                return new IdentifierTypeNode('mixed');\n            }\n\n            if (\\count($filtered) === 1) {\n                return $filtered[0];\n            }\n\n            return new IntersectionTypeNode($filtered);\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            $newItems = [];\n            foreach ($node->items as $item) {\n                $newItems[] = new ArrayShapeItemNode(\n                    $item->keyName,\n                    $item->optional,\n                    self::substituteAliases($item->valueType, $aliases)\n                );\n            }\n\n            $newUnsealed = null;\n            if ($node->unsealedType !== null) {\n                $unsealedKey = $node->unsealedType->keyType !== null\n                    ? self::substituteAliases($node->unsealedType->keyType, $aliases)\n                    : null;\n                $unsealedVal = self::substituteAliases($node->unsealedType->valueType, $aliases);\n                $newUnsealed = new ArrayShapeUnsealedTypeNode($unsealedVal, $unsealedKey);\n            }\n\n            if ($node->sealed) {\n                return ArrayShapeNode::createSealed($newItems, $node->kind);\n            }\n\n            return ArrayShapeNode::createUnsealed($newItems, $newUnsealed, $node->kind);\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            $newItems = [];\n            foreach ($node->items as $item) {\n                $newItems[] = new ObjectShapeItemNode(\n                    $item->keyName,\n                    $item->optional,\n                    self::substituteAliases($item->valueType, $aliases)\n                );\n            }\n\n            return new ObjectShapeNode($newItems);\n        }\n\n        return $node;\n    }\n}\n","/typephp/src/Internal/Generics/TemplateManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Generics;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse PHPStan\\PhpDocParser\\Parser\\TokenIterator;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Docblock\\DocblockExtractor;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Resolver\\HierarchyResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\FileFilter;\nuse TypePHP\\Internal\\Util\\StubManager;\nuse WeakMap;\n\n/**\n * Manages generic template bindings for object instances (via WeakMap) and static/method call stack frames.\n *\n * @internal\n */\nfinal class TemplateManager\n{\n    /**\n     * WeakMap storing generic template bindings per object instance.\n     *\n     * @var WeakMap<object, array<string, TypeNode>>|null\n     */\n    private static ?WeakMap $instanceTemplateBindings = null;\n\n    /**\n     * Call stack frames storing template bindings per function or method call.\n     *\n     * @var array<string, list<array<string, TypeNode>>>\n     */\n    private static array $callStackBindings = [];\n\n    /**\n     * Cache for resolved hierarchy templates and variances per class name.\n     *\n     * @var array<string, array{0: array<string, TemplateTagValueNode>, 1: array<string, string>}>\n     */\n    private static array $classHierarchyTemplatesCache = [];\n\n    /**\n     * Cache for inherited template bindings per class name.\n     *\n     * @var array<string, array<string, TypeNode>>\n     */\n    private static array $classInheritedBindingsCache = [];\n\n    /**\n     * In-memory 2D cache for subclass hierarchy (is_a) lookups: [$sub][$super] => bool.\n     *\n     * @var array<string, array<string, bool>>\n     */\n    private static array $subclassCache = [];\n\n    /**\n     * In-memory cache for real type symbol verification (class/interface/trait/enum existence).\n     *\n     * @var array<string, bool>\n     */\n    private static array $realTypeSymbolCache = [];\n\n    /**\n     * Temporary storage for an original object instance being cloned.\n     */\n    public static ?object $pendingCloneSource = null;\n\n    /**\n     * Fast O(1) hashmap for recognized key template names.\n     *\n     * @var array<string, true>\n     */\n    private const KEY_TEMPLATE_NAMES = [\n        'tkey' => true,\n        'key' => true,\n        'k' => true,\n    ];\n\n    /**\n     * Fast O(1) hashmap for class context self-referencing keywords.\n     *\n     * @var array<string, true>\n     */\n    private const CONTEXT_SELF_REFERENCES = [\n        'self' => true,\n        'static' => true,\n        '$this' => true,\n    ];\n\n    /**\n     * O(1) direct hash-table matrix for scalar subtype relationships.\n     *\n     * @var array<string, array<string, bool>>\n     */\n    private const SCALAR_SUBTYPES = [\n        'int' => [\n            'int' => true,\n            'integer' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n        ],\n        'integer' => [\n            'int' => true,\n            'integer' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n        ],\n        'string' => [\n            'string' => true,\n            'non-empty-string' => true,\n            'numeric-string' => true,\n            'lowercase-string' => true,\n            'non-empty-lowercase-string' => true,\n            'uppercase-string' => true,\n            'non-empty-uppercase-string' => true,\n            'class-string' => true,\n            'interface-string' => true,\n            'trait-string' => true,\n            'enum-string' => true,\n            'callable-string' => true,\n            'literal-string' => true,\n            'truthy-string' => true,\n            'non-falsy-string' => true,\n        ],\n        'float' => [\n            'float' => true,\n            'double' => true,\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n        ],\n        'double' => [\n            'float' => true,\n            'double' => true,\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n        ],\n        'bool' => [\n            'bool' => true,\n            'boolean' => true,\n            'true' => true,\n            'false' => true,\n        ],\n        'boolean' => [\n            'bool' => true,\n            'boolean' => true,\n            'true' => true,\n            'false' => true,\n        ],\n        'array-key' => [\n            'array-key' => true,\n            'int' => true,\n            'integer' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n            'string' => true,\n            'non-empty-string' => true,\n            'numeric-string' => true,\n            'lowercase-string' => true,\n            'non-empty-lowercase-string' => true,\n            'uppercase-string' => true,\n            'non-empty-uppercase-string' => true,\n            'class-string' => true,\n            'interface-string' => true,\n            'trait-string' => true,\n            'enum-string' => true,\n            'callable-string' => true,\n            'literal-string' => true,\n            'truthy-string' => true,\n            'non-falsy-string' => true,\n        ],\n        'numeric' => [\n            'numeric' => true,\n            'number' => true,\n            'int' => true,\n            'integer' => true,\n            'float' => true,\n            'double' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n            'numeric-string' => true,\n        ],\n        'number' => [\n            'numeric' => true,\n            'number' => true,\n            'int' => true,\n            'integer' => true,\n            'float' => true,\n            'double' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n            'numeric-string' => true,\n        ],\n        'scalar' => [\n            'scalar' => true,\n            'int' => true,\n            'integer' => true,\n            'string' => true,\n            'float' => true,\n            'double' => true,\n            'bool' => true,\n            'boolean' => true,\n            'positive-int' => true,\n            'negative-int' => true,\n            'non-positive-int' => true,\n            'non-negative-int' => true,\n            'non-zero-int' => true,\n            'unsigned-int' => true,\n            'positive-float' => true,\n            'negative-float' => true,\n            'non-positive-float' => true,\n            'non-negative-float' => true,\n            'non-zero-float' => true,\n            'non-empty-string' => true,\n            'numeric-string' => true,\n            'lowercase-string' => true,\n            'non-empty-lowercase-string' => true,\n            'uppercase-string' => true,\n            'non-empty-uppercase-string' => true,\n            'class-string' => true,\n            'interface-string' => true,\n            'trait-string' => true,\n            'enum-string' => true,\n            'callable-string' => true,\n            'literal-string' => true,\n            'truthy-string' => true,\n            'non-falsy-string' => true,\n            'true' => true,\n            'false' => true,\n        ],\n    ];\n\n    /**\n     * O(1) hashmap for collection and iterable subtype relationships.\n     *\n     * @var array<string, array<string, bool>>\n     */\n    private const COLLECTION_SUBTYPES = [\n        'array' => [\n            'array' => true,\n            'list' => true,\n            'non-empty-array' => true,\n            'non-empty-list' => true,\n        ],\n        'list' => [\n            'list' => true,\n            'non-empty-list' => true,\n        ],\n        'iterable' => [\n            'iterable' => true,\n            'array' => true,\n            'list' => true,\n            'non-empty-array' => true,\n            'non-empty-list' => true,\n            'traversable' => true,\n        ],\n        'traversable' => [\n            'traversable' => true,\n        ],\n    ];\n\n    /**\n     * O(1) lookup set for valid supertypes of integer ranges and numeric literals.\n     *\n     * @var array<string, bool>\n     */\n    private const INT_SUPERTYPES = [\n        'int' => true,\n        'integer' => true,\n        'array-key' => true,\n        'numeric' => true,\n        'number' => true,\n        'scalar' => true,\n    ];\n\n    /**\n     * O(1) lookup set for valid supertypes of string literals and class-string<T>.\n     *\n     * @var array<string, bool>\n     */\n    private const STRING_SUPERTYPES = [\n        'string' => true,\n        'array-key' => true,\n        'scalar' => true,\n    ];\n\n    private static ?IdentifierTypeNode $intNode = null;\n\n    private static ?IdentifierTypeNode $stringNode = null;\n\n    private static ?IdentifierTypeNode $floatNode = null;\n\n    private static ?IdentifierTypeNode $boolNode = null;\n\n    private static ?IdentifierTypeNode $listNode = null;\n\n    private static ?IdentifierTypeNode $arrayNode = null;\n\n    private static ?IdentifierTypeNode $nullNode = null;\n\n    private static ?IdentifierTypeNode $mixedNode = null;\n\n    /**\n     * @var array<string, IdentifierTypeNode>\n     */\n    public static array $classNodeCache = [];\n\n    /**\n     * In-memory cache for declared method templates per function.\n     *\n     * @var array<string, array<string, TemplateTagValueNode>>\n     */\n    private static array $methodTemplatesCache = [];\n\n    /**\n     * In-memory cache for isMethodTemplate checks per function and template name: [$function][$templateName] => bool.\n     *\n     * @var array<string, array<string, bool>>\n     */\n    private static array $isMethodTemplateCache = [];\n\n    /**\n     * Stack storing pending generic instantiations for constructors.\n     *\n     * @var list<array{typeString: string, file: string, targetClass: string}>\n     */\n    private static array $pendingInstantiations = [];\n\n    /**\n     * Resets all static generic template bindings, call stack frames, and method template caches.\n     */\n    public static function reset(): void\n    {\n        self::$instanceTemplateBindings = null;\n        self::$callStackBindings = [];\n        self::$classHierarchyTemplatesCache = [];\n        self::$classInheritedBindingsCache = [];\n        self::$subclassCache = [];\n        self::$realTypeSymbolCache = [];\n        self::$pendingCloneSource = null;\n        self::$methodTemplatesCache = [];\n        self::$isMethodTemplateCache = [];\n        self::$pendingInstantiations = [];\n    }\n\n    /**\n     * Pushes a pending generic instantiation for a constructor.\n     */\n    public static function pushPendingInstantiation(string $typeString, string $file): void\n    {\n        $pos = strpos($typeString, '<');\n        $rawClass = $pos !== false ? trim(substr($typeString, 0, $pos)) : $typeString;\n        $targetClass = SpecialTypeResolver::resolveFqcnForFile($rawClass, $file);\n\n        self::$pendingInstantiations[] = [\n            'typeString' => $typeString,\n            'file' => $file,\n            'targetClass' => $targetClass,\n        ];\n    }\n\n    /**\n     * Pops the last pending generic instantiation for a constructor.\n     */\n    public static function popPendingInstantiation(): void\n    {\n        array_pop(self::$pendingInstantiations);\n    }\n\n    /**\n     * Applies the last pending generic instantiation for a constructor to the given instance.\n     */\n    public static function applyPendingInstantiation(object $instance): void\n    {\n        if (! Config::isInlineGenericsEnabled() || self::$pendingInstantiations === []) {\n            return;\n        }\n\n        $pending = end(self::$pendingInstantiations);\n        if ($pending !== false && is_a($instance, $pending['targetClass'])) {\n            self::bindInstance($instance, $pending['typeString'], $pending['file']);\n        }\n    }\n\n    /**\n     * Retrieves inherited class-level template bindings for a class name.\n     *\n     * @return array<string, TypeNode>\n     */\n    public static function getClassInheritedBindings(string $className): array\n    {\n        if (isset(self::$classInheritedBindingsCache[$className])) {\n            return self::$classInheritedBindingsCache[$className];\n        }\n\n        if (! class_exists($className, false) && ! class_exists($className) && ! interface_exists($className) && ! trait_exists($className)) {\n            return self::$classInheritedBindingsCache[$className] = [];\n        }\n\n        return self::$classInheritedBindingsCache[$className] = self::computeClassInheritedBindings($className);\n    }\n\n    /**\n     * Normalizes generic type arguments when a single type argument is supplied\n     * for a 2-template collection/map whose first template is a key type (TKey of array-key).\n     *\n     * @param array<TypeNode> $genericTypes\n     * @param array<TemplateTagValueNode> $templateList\n     *\n     * @return array<TypeNode>\n     */\n    public static function normalizeGenericArguments(array $genericTypes, array $templateList): array\n    {\n        $genericTypes = array_values($genericTypes);\n        $templateList = array_values($templateList);\n\n        if (\\count($genericTypes) === 1 && \\count($templateList) === 2) {\n            $firstTemplate = $templateList[0];\n            $firstBound = $firstTemplate->bound !== null ? strtolower((string) $firstTemplate->bound) : '';\n            $firstName = strtolower($firstTemplate->name);\n\n            $isKeyTemplate = $firstBound === 'array-key' || isset(self::KEY_TEMPLATE_NAMES[$firstName]);\n\n            if ($isKeyTemplate) {\n                $defaultKeyNode = $firstTemplate->default ?? $firstTemplate->bound ?? new IdentifierTypeNode('array-key');\n\n                return [$defaultKeyNode, $genericTypes[0]];\n            }\n        }\n\n        return $genericTypes;\n    }\n\n    /**\n     * Copies bound generic template types from a source object to a cloned target object.\n     */\n    public static function copyInstanceBindings(object $source, object $target): void\n    {\n        if (self::$instanceTemplateBindings !== null && isset(self::$instanceTemplateBindings[$source])) {\n            $bindings = self::$instanceTemplateBindings[$source];\n            self::$instanceTemplateBindings[$target] = $bindings;\n        }\n    }\n\n    /**\n     * Pushes a new empty call frame onto the stack for a function execution.\n     */\n    public static function pushCallFrame(string $function): void\n    {\n        self::$callStackBindings[$function][] = [];\n    }\n\n    /**\n     * Pops the top call frame from the stack upon function completion or exception.\n     */\n    public static function popCallFrame(string $function): void\n    {\n        if (isset(self::$callStackBindings[$function])) {\n            array_pop(self::$callStackBindings[$function]);\n            if (self::$callStackBindings[$function] === []) {\n                unset(self::$callStackBindings[$function]);\n            }\n        }\n    }\n\n    /**\n     * Clears and initializes a fresh call frame for a function call.\n     *\n     * @param array<string, TemplateTagValueNode> $templates\n     */\n    public static function clearCallBindings(string $function, array $templates): void\n    {\n        self::pushCallFrame($function);\n    }\n\n    /**\n     * Retrieves currently bound template types for a function call or object instance / static class.\n     *\n     * @param array<string, TemplateTagValueNode> $templates\n     *\n     * @return array<string, TypeNode>\n     */\n    public static function getBoundTemplates(string $function, object|string|null $thisOrClass, array $templates): array\n    {\n        $bindings = [];\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($thisObj !== null) {\n            self::ensureInstanceInherited($thisObj);\n\n            if (isset(self::$instanceTemplateBindings[$thisObj])) {\n                $bindings = self::$instanceTemplateBindings[$thisObj];\n            }\n\n            $methodTemplates = self::getMethodTemplates($function);\n            if ($methodTemplates !== []) {\n                foreach ($methodTemplates as $methodTName => $_) {\n                    unset($bindings[$methodTName]);\n                }\n            }\n        } else {\n            $className = \\is_string($thisOrClass) && $thisOrClass !== ''\n                ? $thisOrClass\n                : (str_contains($function, '::') ? explode('::', $function, 2)[0] : '');\n\n            if ($className !== '' && (class_exists($className, false) || class_exists($className) || interface_exists($className) || trait_exists($className))) {\n                $classBindings = self::getClassInheritedBindings($className);\n                $bindings = $classBindings;\n\n                $methodTemplates = self::getMethodTemplates($function);\n                if ($methodTemplates !== []) {\n                    foreach ($methodTemplates as $methodTName => $_) {\n                        unset($bindings[$methodTName]);\n                    }\n                }\n            }\n        }\n\n        $topFrame = self::getTopCallFrame($function);\n        if ($topFrame !== null) {\n            $bindings = $bindings === []\n                ? $topFrame\n                : [...$bindings, ...$topFrame];\n        }\n\n        return $bindings;\n    }\n\n    public static function hasInstanceBindings(object $instance): bool\n    {\n        return self::$instanceTemplateBindings !== null && isset(self::$instanceTemplateBindings[$instance]);\n    }\n\n    /**\n     * Retrieves all bound template TypeNodes for a specific object instance.\n     *\n     * @return array<string, TypeNode>\n     */\n    public static function getBoundTemplatesForInstance(object $instance): array\n    {\n        self::ensureInstanceInherited($instance);\n\n        if (self::$instanceTemplateBindings !== null && isset(self::$instanceTemplateBindings[$instance])) {\n            return self::$instanceTemplateBindings[$instance];\n        }\n\n        return [];\n    }\n\n    /**\n     * Retrieves all declared template variances ('covariant', 'contravariant', or 'invariant') for an object instance.\n     *\n     * @return array<string, string>\n     */\n    public static function getTemplateVariances(object $instance): array\n    {\n        $className = $instance::class;\n\n        try {\n            $stubDoc = StubManager::getClassDoc($className);\n            $ref = new \\ReflectionClass($instance);\n            $classDoc = $stubDoc ?? $ref->getDocComment();\n\n            if ($classDoc !== false && $classDoc !== null) {\n                $classPhpDocNode = DocblockExtractor::parseDocString($classDoc);\n\n                return DocblockExtractor::extractTemplateVariances($classPhpDocNode);\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore reflection errors\n        }\n\n        return [];\n    }\n\n    /**\n     * Checks if a template name is declared as a method-level template on the given function/method.\n     */\n    public static function isMethodTemplate(string $function, string $templateName): bool\n    {\n        if ($function === '' || ! str_contains($function, '::')) {\n            return false;\n        }\n\n        if (isset(self::$isMethodTemplateCache[$function][$templateName])) {\n            return self::$isMethodTemplateCache[$function][$templateName];\n        }\n\n        $methodTemplates = self::getMethodTemplates($function);\n\n        return self::$isMethodTemplateCache[$function][$templateName] = isset($methodTemplates[$templateName]);\n    }\n\n    /**\n     * Returns declared method-level templates for the given function or method.\n     *\n     * @return array<string, TemplateTagValueNode>\n     */\n    public static function getMethodTemplates(string $function): array\n    {\n        if ($function === '' || ! str_contains($function, '::')) {\n            return [];\n        }\n\n        if (isset(self::$methodTemplatesCache[$function])) {\n            return self::$methodTemplatesCache[$function];\n        }\n\n        return self::$methodTemplatesCache[$function] = DocblockParser::parse($function)['templates'];\n    }\n\n    /**\n     * Checks if a template name is bound in the current instance, static class, or call stack frame.\n     */\n    public static function isBound(string $function, object|string|null $thisOrClass, string $templateName): bool\n    {\n        $topFrame = self::getTopCallFrame($function);\n        if ($topFrame !== null && isset($topFrame[$templateName])) {\n            return true;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($thisObj !== null) {\n            self::ensureInstanceInherited($thisObj);\n\n            if (self::isMethodTemplate($function, $templateName)) {\n                return false;\n            }\n\n            return isset(self::$instanceTemplateBindings[$thisObj][$templateName]);\n        }\n\n        $className = \\is_string($thisOrClass) && $thisOrClass !== ''\n            ? $thisOrClass\n            : (str_contains($function, '::') ? explode('::', $function, 2)[0] : '');\n\n        if ($className !== '' && (class_exists($className, false) || class_exists($className) || interface_exists($className) || trait_exists($className))) {\n            if (self::isMethodTemplate($function, $templateName)) {\n                return false;\n            }\n\n            $classBindings = self::getClassInheritedBindings($className);\n\n            return isset($classBindings[$templateName]);\n        }\n\n        return false;\n    }\n\n    /**\n     * Retrieves the bound TypeNode for a template name from instance, static class, or call stack context.\n     */\n    public static function getBoundType(string $function, object|string|null $thisOrClass, string $templateName): ?TypeNode\n    {\n        $topFrame = self::getTopCallFrame($function);\n        if ($topFrame !== null && isset($topFrame[$templateName])) {\n            return $topFrame[$templateName];\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n\n        if ($thisObj !== null) {\n            self::ensureInstanceInherited($thisObj);\n\n            if (self::isMethodTemplate($function, $templateName)) {\n                return null;\n            }\n\n            return self::$instanceTemplateBindings[$thisObj][$templateName] ?? null;\n        }\n\n        $className = \\is_string($thisOrClass) && $thisOrClass !== ''\n            ? $thisOrClass\n            : (str_contains($function, '::') ? explode('::', $function, 2)[0] : '');\n\n        if ($className !== '' && (class_exists($className, false) || class_exists($className) || interface_exists($className) || trait_exists($className))) {\n            if (self::isMethodTemplate($function, $templateName)) {\n                return null;\n            }\n\n            $classBindings = self::getClassInheritedBindings($className);\n\n            return $classBindings[$templateName] ?? null;\n        }\n\n        return null;\n    }\n\n    /**\n     * Binds an inferred TypeNode to a template parameter for an instance or call stack frame.\n     */\n    public static function bindTemplate(string $function, ?object $thisObj, string $templateName, TypeNode $inferredType): void\n    {\n        if ($thisObj !== null && ! self::isMethodTemplate($function, $templateName)) {\n            self::$instanceTemplateBindings ??= new WeakMap();\n            $bindings = self::$instanceTemplateBindings[$thisObj] ?? [];\n            $bindings[$templateName] = $inferredType;\n            self::$instanceTemplateBindings[$thisObj] = $bindings;\n        } else {\n            if (! self::hasCallFrame($function)) {\n                self::$callStackBindings[$function][] = [];\n            }\n            $lastIndex = \\count(self::$callStackBindings[$function]) - 1;\n            self::$callStackBindings[$function][$lastIndex][$templateName] = $inferredType;\n        }\n    }\n\n    /**\n     * Binds generic template types to an object instance or validates variance against an existing binding.\n     */\n    public static function bindInstanceFromNode(object $instance, GenericTypeNode $typeNode, string $context = '', bool $forceBind = false): ?ErrorMessage\n    {\n        $className = $typeNode->type->name;\n        if (isset(self::CONTEXT_SELF_REFERENCES[strtolower($className)])) {\n            $className = $instance::class;\n        }\n\n        if (! is_a($instance, $className) || ! ClassNameValidator::isValid($className) || ! self::isRealTypeSymbol($className)) {\n            return null;\n        }\n\n        self::resolveInheritedTemplates($instance, $className);\n\n        try {\n            /** @var class-string<object> $className */\n            $ref = new \\ReflectionClass($className);\n            [$templates, $classVariances] = self::collectHierarchyTemplatesAndVariances($ref);\n\n            self::$instanceTemplateBindings ??= new WeakMap();\n            $templateList = array_values($templates);\n            $normalizedTypeArgs = self::normalizeGenericArguments($typeNode->genericTypes, $templateList);\n\n            foreach ($templateList as $index => $templateTag) {\n                if (! isset($normalizedTypeArgs[$index])) {\n                    continue;\n                }\n\n                $err = self::bindSingleTemplateArgument($instance, $className, $normalizedTypeArgs[$index], $typeNode->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT, $templateTag, $classVariances, $context, $forceBind);\n                if ($err !== null) {\n                    return $err;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore reflection or parsing errors\n        }\n\n        return null;\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $ref\n     *\n     * @return array{0: array<string, TemplateTagValueNode>, 1: array<string, string>}\n     */\n    private static function collectHierarchyTemplatesAndVariances(\\ReflectionClass $ref): array\n    {\n        $className = $ref->getName();\n        if (isset(self::$classHierarchyTemplatesCache[$className])) {\n            return self::$classHierarchyTemplatesCache[$className];\n        }\n\n        $classHierarchy = HierarchyResolver::getClassHierarchy($ref);\n        $templates = [];\n        $classVariances = [];\n\n        foreach ($classHierarchy as $hierClass) {\n            $hierClassName = $hierClass->getName();\n            $stubDoc = StubManager::getClassDoc($hierClassName);\n            $classDoc = $stubDoc ?? $hierClass->getDocComment();\n\n            if ($classDoc === false || $classDoc === null) {\n                continue;\n            }\n\n            $classPhpDocNode = DocblockExtractor::parseDocString($classDoc);\n            $hierTemplates = DocblockExtractor::extractTemplates($classPhpDocNode);\n            $hierVariances = DocblockExtractor::extractTemplateVariances($classPhpDocNode);\n\n            foreach ($hierTemplates as $tName => $tagNode) {\n                if (! isset($templates[$tName])) {\n                    if ($tagNode->bound !== null || $tagNode->default !== null) {\n                        $tagNode = new TemplateTagValueNode(\n                            $tagNode->name,\n                            $tagNode->bound !== null ? SpecialTypeResolver::resolve($tagNode->bound, $hierClass) : null,\n                            $tagNode->description,\n                            $tagNode->default !== null ? SpecialTypeResolver::resolve($tagNode->default, $hierClass) : null\n                        );\n                    }\n\n                    $templates[$tName] = $tagNode;\n                    $classVariances[$tName] = match ($hierVariances[$tName] ?? 'invariant') {\n                        'covariant' => GenericTypeNode::VARIANCE_COVARIANT,\n                        'contravariant' => GenericTypeNode::VARIANCE_CONTRAVARIANT,\n                        default => GenericTypeNode::VARIANCE_INVARIANT,\n                    };\n                }\n            }\n        }\n\n        return self::$classHierarchyTemplatesCache[$className] = [$templates, $classVariances];\n    }\n\n    /**\n     * @param array<string, string> $classVariances\n     */\n    private static function bindSingleTemplateArgument(\n        object $instance,\n        string $className,\n        TypeNode $expectedTypeNode,\n        string $usageVariance,\n        TemplateTagValueNode $templateTag,\n        array $classVariances,\n        string $context,\n        bool $forceBind\n    ): ?ErrorMessage {\n        if ($expectedTypeNode instanceof IdentifierTypeNode) {\n            $isBuiltIn = SpecialTypeResolver::isBuiltInTypeKeyword($expectedTypeNode->name);\n            $isRealType = self::isRealTypeSymbol($expectedTypeNode->name);\n\n            if (! $isBuiltIn && ! $isRealType) {\n                return null;\n            }\n        }\n\n        $isWildcardOrMixed = ($expectedTypeNode instanceof IdentifierTypeNode && ($expectedTypeNode->name === '*' || strtolower($expectedTypeNode->name) === 'mixed'));\n\n        if ($templateTag->bound !== null && ! $isWildcardOrMixed) {\n            $satisfiesBound = self::checkVariance($expectedTypeNode, $templateTag->bound, GenericTypeNode::VARIANCE_COVARIANT);\n\n            if (! $satisfiesBound) {\n                $contextPrefix = $context !== '' ? (str_ends_with($context, ':') ? $context . ' ' : $context . ': ') : ' ';\n\n                return ErrorFactory::createError(\n                    $contextPrefix . \"Generic type argument {$expectedTypeNode} does not satisfy upper bound {$templateTag->bound} of template {$templateTag->name} in {$className}\"\n                );\n            }\n        }\n\n        self::$instanceTemplateBindings ??= new WeakMap();\n\n        $declaredVariance = $classVariances[$templateTag->name] ?? GenericTypeNode::VARIANCE_INVARIANT;\n        $isReturnContext = str_contains($context, 'Return value');\n        $strictInvariance = Config::isStrictReturnGenericInvarianceEnabled();\n\n        $variance = match (true) {\n            $usageVariance !== GenericTypeNode::VARIANCE_INVARIANT => $usageVariance,\n            $declaredVariance === GenericTypeNode::VARIANCE_CONTRAVARIANT => GenericTypeNode::VARIANCE_CONTRAVARIANT,\n            $isReturnContext && ! $strictInvariance => GenericTypeNode::VARIANCE_COVARIANT,\n            default => $declaredVariance,\n        };\n\n        $templateName = $templateTag->name;\n        $existingBindings = self::$instanceTemplateBindings[$instance] ?? [];\n\n        if (isset($existingBindings[$templateName])) {\n            $existingTypeNode = $existingBindings[$templateName];\n            $valid = self::checkVariance($existingTypeNode, $expectedTypeNode, $variance);\n\n            if (! $valid) {\n                if ($forceBind) {\n                    $bindings = self::$instanceTemplateBindings[$instance] ?? [];\n                    $bindings[$templateName] = $expectedTypeNode;\n                    self::$instanceTemplateBindings[$instance] = $bindings;\n\n                    return null;\n                }\n\n                $isDefaultOrBound = ($existingTypeNode instanceof IdentifierTypeNode) && (\n                    strtolower($existingTypeNode->name) === 'mixed'\n                    || strtolower($existingTypeNode->name) === 'array-key'\n                    || ($templateTag->bound !== null && (string) $existingTypeNode === (string) $templateTag->bound)\n                    || ($templateTag->default !== null && (string) $existingTypeNode === (string) $templateTag->default)\n                );\n\n                if (self::checkVariance($expectedTypeNode, $existingTypeNode, GenericTypeNode::VARIANCE_COVARIANT)) {\n                    if ($isDefaultOrBound || ($isReturnContext && ! $strictInvariance)) {\n                        $bindings = self::$instanceTemplateBindings[$instance] ?? [];\n                        $bindings[$templateName] = $expectedTypeNode;\n                        self::$instanceTemplateBindings[$instance] = $bindings;\n\n                        return null;\n                    }\n                }\n\n                if ($isReturnContext) {\n                    $isWrapping = ($expectedTypeNode instanceof ArrayTypeNode)\n                        && self::checkVariance($expectedTypeNode->type, $existingTypeNode, GenericTypeNode::VARIANCE_COVARIANT);\n\n                    $isUnwrapping = ($existingTypeNode instanceof ArrayTypeNode)\n                        && self::checkVariance($expectedTypeNode, $existingTypeNode->type, GenericTypeNode::VARIANCE_COVARIANT);\n\n                    if ($isWrapping || $isUnwrapping) {\n                        $bindings = self::$instanceTemplateBindings[$instance] ?? [];\n                        $bindings[$templateName] = $expectedTypeNode;\n                        self::$instanceTemplateBindings[$instance] = $bindings;\n\n                        return null;\n                    }\n                }\n\n                $contextPrefix = $context !== '' ? (str_ends_with($context, ':') ? $context . ' ' : $context . ' ') : ' ';\n\n                return ErrorFactory::createError(\n                    $contextPrefix . \"expects {$className}<{$variance} {$expectedTypeNode}>, but {$className}<{$existingTypeNode}> was given\"\n                );\n            }\n        }\n\n        if ($forceBind || ! isset($existingBindings[$templateName])) {\n            $bindings = self::$instanceTemplateBindings[$instance] ?? [];\n            $bindings[$templateName] = $isWildcardOrMixed && $templateTag->bound !== null ? $templateTag->bound : $expectedTypeNode;\n            self::$instanceTemplateBindings[$instance] = $bindings;\n        }\n\n        return null;\n    }\n\n    /**\n     * Resolves and binds parent class (@extends), interface (@implements), and trait (@use) template mappings.\n     * Respects Vendor Isolation by skipping docblocks from excluded vendor ancestor files unless stubbed.\n     */\n    public static function resolveInheritedTemplates(object $instance, string $targetClassName): void\n    {\n        $actualClassName = $instance::class;\n        self::$instanceTemplateBindings ??= new WeakMap();\n\n        if (isset(self::$classInheritedBindingsCache[$actualClassName])) {\n            /** @var array<string, TypeNode> $cachedBindings */\n            $cachedBindings = self::$classInheritedBindingsCache[$actualClassName];\n            $existing = self::$instanceTemplateBindings[$instance] ?? [];\n            self::$instanceTemplateBindings[$instance] = [...$cachedBindings, ...$existing];\n\n            return;\n        }\n\n        $resolvedClassBindings = self::computeClassInheritedBindings($actualClassName);\n        self::$classInheritedBindingsCache[$actualClassName] = $resolvedClassBindings;\n\n        $existing = self::$instanceTemplateBindings[$instance] ?? [];\n        self::$instanceTemplateBindings[$instance] = [...$resolvedClassBindings, ...$existing];\n    }\n\n    /**\n     * @return array<string, TypeNode>\n     */\n    private static function computeClassInheritedBindings(string $actualClassName): array\n    {\n        /** @var array<string, TypeNode> $bindings */\n        $bindings = [];\n\n        if (! class_exists($actualClassName, false) && ! class_exists($actualClassName) && ! interface_exists($actualClassName) && ! trait_exists($actualClassName)) {\n            return [];\n        }\n\n        try {\n            /** @var class-string<object> $actualClassName */\n            $ref = new \\ReflectionClass($actualClassName);\n            $classHierarchy = HierarchyResolver::getClassHierarchy($ref);\n\n            foreach ($classHierarchy as $hierClass) {\n                $fileName = $hierClass->getFileName();\n                $hierClassName = $hierClass->getName();\n                $stubDoc = StubManager::getClassDoc($hierClassName);\n\n                if ($stubDoc === null && $hierClass->getName() !== $actualClassName && FileFilter::isFileExcluded($fileName !== false ? $fileName : null)) {\n                    continue;\n                }\n\n                $docsToInspect = self::collectDocsForClassHierarchyMember($hierClass);\n\n                foreach ($docsToInspect as $rawDoc) {\n                    $classPhpDocNode = DocblockExtractor::parseDocString($rawDoc);\n\n                    $declaredTemplateNames = [];\n                    foreach ($classPhpDocNode->getTags() as $tag) {\n                        if ($tag->value instanceof TemplateTagValueNode) {\n                            $declaredTemplateNames[$tag->value->name] = true;\n                        }\n                    }\n\n                    $inheritedTags = DocblockExtractor::getInheritedTags($classPhpDocNode);\n\n                    foreach ($inheritedTags as $inheritedTag) {\n                        $genericTypeNode = $inheritedTag->type;\n                        if ($genericTypeNode instanceof GenericTypeNode) {\n                            self::collectInheritedGenericTagBindings($genericTypeNode, $hierClass, $declaredTemplateNames, $actualClassName, $bindings);\n                        }\n                    }\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore reflection or parsing errors\n        }\n\n        return $bindings;\n    }\n\n    /**\n     * @param array<string, bool> $declaredTemplateNames\n     * @param array<string, TypeNode> $bindings\n     * @param \\ReflectionClass<object> $hierClass\n     */\n    private static function collectInheritedGenericTagBindings(\n        GenericTypeNode $genericTypeNode,\n        \\ReflectionClass $hierClass,\n        array $declaredTemplateNames,\n        string $actualClassName,\n        array &$bindings\n    ): void {\n        $parentName = SpecialTypeResolver::resolveFqcn($genericTypeNode->type->name, $hierClass);\n        $isHierarchyMember = is_a($actualClassName, $parentName, true) || trait_exists($parentName);\n\n        if (! ClassNameValidator::isValid($parentName) || ! $isHierarchyMember) {\n            return;\n        }\n\n        if (! self::isRealTypeSymbol($parentName)) {\n            return;\n        }\n\n        try {\n            $stubDoc = StubManager::getClassDoc($parentName);\n            /** @var class-string<object> $parentName */\n            $parentRef = new \\ReflectionClass($parentName);\n            $parentDoc = $stubDoc ?? $parentRef->getDocComment();\n\n            if ($parentDoc === false || $parentDoc === null) {\n                return;\n            }\n\n            $parentPhpDocNode = DocblockExtractor::parseDocString($parentDoc);\n            $parentTemplateNames = array_keys(DocblockExtractor::extractTemplates($parentPhpDocNode));\n            $parentTemplateNodes = array_values(DocblockExtractor::extractTemplates($parentPhpDocNode));\n            $normalizedGenericTypes = self::normalizeGenericArguments($genericTypeNode->genericTypes, $parentTemplateNodes);\n\n            foreach ($parentTemplateNames as $idx => $templateName) {\n                if (isset($normalizedGenericTypes[$idx])) {\n                    $resolved = self::resolveTypeNodeAst($normalizedGenericTypes[$idx], $hierClass);\n\n                    if ($resolved instanceof IdentifierTypeNode) {\n                        $isBuiltIn = SpecialTypeResolver::isBuiltInTypeKeyword($resolved->name);\n                        $isRealType = self::isRealTypeSymbol($resolved->name);\n\n                        if (! $isBuiltIn && ! $isRealType) {\n                            continue;\n                        }\n\n                        if (isset($declaredTemplateNames[$resolved->name])) {\n                            continue;\n                        }\n                    }\n\n                    $bindings[$templateName] = $resolved;\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore reflection errors\n        }\n    }\n\n    /**\n     * @param \\ReflectionClass<object> $hierClass\n     *\n     * @return array<int, string>\n     */\n    private static function collectDocsForClassHierarchyMember(\\ReflectionClass $hierClass): array\n    {\n        $docs = [];\n\n        $stubDoc = StubManager::getClassDoc($hierClass->getName());\n        $classDoc = $stubDoc ?? $hierClass->getDocComment();\n        if ($classDoc !== false && $classDoc !== null) {\n            $docs[] = $classDoc;\n        }\n\n        foreach (SpecialTypeResolver::getClassTraitUseDocs($hierClass->getName()) as $tDoc) {\n            $docs[] = $tDoc;\n        }\n\n        return $docs;\n    }\n\n    /**\n     * Recursively checks if an existing type node satisfies an expected type node under a given variance modifier.\n     */\n    public static function checkVariance(TypeNode $existing, TypeNode $expected, string $variance): bool\n    {\n        $existingStr = (string) $existing;\n        $expectedStr = (string) $expected;\n\n        if ($existingStr === $expectedStr || $variance === GenericTypeNode::VARIANCE_BIVARIANT || $expectedStr === 'mixed' || $expectedStr === '*') {\n            return true;\n        }\n\n        $lowerExpected = strtolower($expectedStr);\n        $lowerExisting = strtolower($existingStr);\n\n        if ($lowerExpected === 'object' && ClassNameValidator::isValid($existingStr) && self::isRealTypeSymbol($existingStr)) {\n            return true;\n        }\n\n        if (self::isScalarSubtype($lowerExisting, $lowerExpected)) {\n            return true;\n        }\n\n        if ($variance === GenericTypeNode::VARIANCE_COVARIANT && isset(self::COLLECTION_SUBTYPES[$lowerExpected])) {\n            $allowedSubtypes = self::COLLECTION_SUBTYPES[$lowerExpected];\n\n            if (isset($allowedSubtypes[$lowerExisting])) {\n                return true;\n            }\n\n            if ($existing instanceof ArrayTypeNode || $existing instanceof ArrayShapeNode) {\n                return $lowerExpected === 'array' || $lowerExpected === 'iterable';\n            }\n\n            if ($existing instanceof GenericTypeNode && isset($allowedSubtypes[strtolower($existing->type->name)])) {\n                return true;\n            }\n        }\n\n        if ($expected instanceof UnionTypeNode) {\n            return self::checkExpectedUnionVariance($existing, $expected, $variance);\n        }\n\n        if ($existing instanceof UnionTypeNode) {\n            return self::checkExistingUnionVariance($existing, $expected, $variance);\n        }\n\n        if ($expected instanceof IntersectionTypeNode) {\n            return self::checkExpectedIntersectionVariance($existing, $expected, $variance);\n        }\n\n        if ($existing instanceof IntersectionTypeNode) {\n            return self::checkExistingIntersectionVariance($existing, $expected, $variance);\n        }\n\n        if ($existing instanceof GenericTypeNode && $expected instanceof GenericTypeNode) {\n            return self::checkNestedGenericVariance($existing, $expected);\n        }\n\n        if ($existing instanceof IdentifierTypeNode && $expected instanceof GenericTypeNode) {\n            if ($variance === GenericTypeNode::VARIANCE_COVARIANT && self::isSubclass($existing->name, $expected->type->name)) {\n                return true;\n            }\n        }\n\n        if ($variance === GenericTypeNode::VARIANCE_COVARIANT) {\n            return self::isSubclass($existingStr, $expectedStr);\n        }\n\n        if ($variance === GenericTypeNode::VARIANCE_CONTRAVARIANT) {\n            return self::isSubclass($expectedStr, $existingStr);\n        }\n\n        return false;\n    }\n\n    /**\n     * O(1) scalar subtype verification.\n     */\n    private static function isScalarSubtype(string $sub, string $super): bool\n    {\n        if (isset(self::SCALAR_SUBTYPES[$super][$sub])) {\n            return true;\n        }\n\n        if ((str_starts_with($sub, 'int<') || is_numeric($sub)) && isset(self::INT_SUPERTYPES[$super])) {\n            return true;\n        }\n\n        if ((str_starts_with($sub, 'class-string<') || ($sub !== '' && ($sub[0] === \"'\" || $sub[0] === '\"'))) && isset(self::STRING_SUPERTYPES[$super])) {\n            return true;\n        }\n\n        return false;\n    }\n\n    private static function checkExpectedUnionVariance(TypeNode $existing, UnionTypeNode $expected, string $variance): bool\n    {\n        if ($variance === GenericTypeNode::VARIANCE_CONTRAVARIANT) {\n            foreach ($expected->types as $unionVariant) {\n                if (! self::checkVariance($existing, $unionVariant, $variance)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        if ($existing instanceof UnionTypeNode) {\n            foreach ($existing->types as $existingVariant) {\n                if (! self::checkExpectedUnionVariance($existingVariant, $expected, $variance)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        foreach ($expected->types as $unionVariant) {\n            if (self::checkVariance($existing, $unionVariant, GenericTypeNode::VARIANCE_COVARIANT)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private static function checkExistingUnionVariance(UnionTypeNode $existing, TypeNode $expected, string $variance): bool\n    {\n        if ($variance === GenericTypeNode::VARIANCE_COVARIANT) {\n            foreach ($existing->types as $existingVariant) {\n                if (! self::checkVariance($existingVariant, $expected, $variance)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        if ($variance === GenericTypeNode::VARIANCE_CONTRAVARIANT) {\n            foreach ($existing->types as $existingVariant) {\n                if (self::checkVariance($existingVariant, $expected, $variance)) {\n                    return true;\n                }\n            }\n\n            return false;\n        }\n\n        return false;\n    }\n\n    private static function checkExpectedIntersectionVariance(TypeNode $existing, IntersectionTypeNode $expected, string $variance): bool\n    {\n        if ($variance === GenericTypeNode::VARIANCE_CONTRAVARIANT) {\n            foreach ($expected->types as $intersectionMember) {\n                if (! self::checkVariance($existing, $intersectionMember, $variance)) {\n                    return true;\n                }\n            }\n\n            return true;\n        }\n\n        foreach ($expected->types as $intersectionMember) {\n            if (! self::checkVariance($existing, $intersectionMember, GenericTypeNode::VARIANCE_COVARIANT)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static function checkExistingIntersectionVariance(IntersectionTypeNode $existing, TypeNode $expected, string $variance): bool\n    {\n        if ($variance === GenericTypeNode::VARIANCE_CONTRAVARIANT) {\n            foreach ($existing->types as $existingMember) {\n                if (! self::checkVariance($existingMember, $expected, $variance)) {\n                    return false;\n                }\n            }\n\n            return true;\n        }\n\n        foreach ($existing->types as $existingMember) {\n            if (self::checkVariance($existingMember, $expected, GenericTypeNode::VARIANCE_COVARIANT)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    private static function checkNestedGenericVariance(GenericTypeNode $existing, GenericTypeNode $expected): bool\n    {\n        if (! is_a($existing->type->name, $expected->type->name, true)) {\n            return false;\n        }\n\n        foreach ($expected->genericTypes as $idx => $expectedInner) {\n            $existingInner = $existing->genericTypes[$idx] ?? new IdentifierTypeNode('mixed');\n            $innerVariance = $expected->variances[$idx] ?? GenericTypeNode::VARIANCE_INVARIANT;\n\n            if (! self::checkVariance($existingInner, $expectedInner, $innerVariance)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    private static function isSubclass(string $sub, string $super): bool\n    {\n        if (isset(self::$subclassCache[$sub][$super])) {\n            return self::$subclassCache[$sub][$super];\n        }\n\n        $baseSub = ($pos = strpos($sub, '<')) !== false ? substr($sub, 0, $pos) : $sub;\n        $baseSuper = ($pos = strpos($super, '<')) !== false ? substr($super, 0, $pos) : $super;\n\n        $baseSub = ltrim(trim($baseSub), '\\\\');\n        $baseSuper = ltrim(trim($baseSuper), '\\\\');\n\n        $result = false;\n\n        if (\n            ClassNameValidator::isValid($baseSub)\n            && ClassNameValidator::isValid($baseSuper)\n            && self::isRealTypeSymbol($baseSub)\n            && self::isRealTypeSymbol($baseSuper)\n        ) {\n            $result = is_a($baseSub, $baseSuper, true);\n        }\n\n        return self::$subclassCache[$sub][$super] = $result;\n    }\n\n    /**\n     * Parses a type string and binds generic templates to an object instance.\n     */\n    public static function bindInstance(object $instance, string $typeString, string $file = ''): object\n    {\n        try {\n            [$typeParser, $lexer] = DocblockExtractor::getTypeParserComponents();\n\n            $tokens = new TokenIterator($lexer->tokenize($typeString));\n            $typeNode = $typeParser->parse($tokens);\n\n            if ($file !== '') {\n                $typeNode = SpecialTypeResolver::resolveForFile($typeNode, $file);\n            }\n\n            if ($typeNode instanceof GenericTypeNode) {\n                self::bindInstanceFromNode($instance, $typeNode, '', true);\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore malformed docblock strings\n        }\n\n        return $instance;\n    }\n\n    /**\n     * Infers a TypeNode AST representation from a raw PHP value using cached singleton nodes.\n     */\n    public static function inferTypeFromValue(mixed $value): TypeNode\n    {\n        if (\\is_int($value)) {\n            return self::$intNode ??= new IdentifierTypeNode('int');\n        }\n        if (\\is_string($value)) {\n            return self::$stringNode ??= new IdentifierTypeNode('string');\n        }\n        if (\\is_float($value)) {\n            return self::$floatNode ??= new IdentifierTypeNode('float');\n        }\n        if (\\is_bool($value)) {\n            return self::$boolNode ??= new IdentifierTypeNode('bool');\n        }\n        if (\\is_array($value)) {\n            return array_is_list($value)\n                ? (self::$listNode ??= new IdentifierTypeNode('list'))\n                : (self::$arrayNode ??= new IdentifierTypeNode('array'));\n        }\n\n        if (\\is_object($value)) {\n            $className = $value::class;\n\n            if (self::$instanceTemplateBindings !== null && isset(self::$instanceTemplateBindings[$value]) && \\count(self::$instanceTemplateBindings[$value]) > 0) {\n                $genericTypes = array_values(self::$instanceTemplateBindings[$value]);\n\n                return new GenericTypeNode(self::$classNodeCache[$className] ??= new IdentifierTypeNode($className), $genericTypes);\n            }\n\n            return self::$classNodeCache[$className] ??= new IdentifierTypeNode($className);\n        }\n\n        if ($value === null) {\n            return self::$nullNode ??= new IdentifierTypeNode('null');\n        }\n\n        return self::$mixedNode ??= new IdentifierTypeNode('mixed');\n    }\n\n    /**\n     * Checks whether a function has at least one active call frame on the stack.\n     */\n    private static function hasCallFrame(string $function): bool\n    {\n        return isset(self::$callStackBindings[$function]);\n    }\n\n    /**\n     * @return array<string, TypeNode>|null\n     */\n    private static function getTopCallFrame(string $function): ?array\n    {\n        if (! isset(self::$callStackBindings[$function]) || self::$callStackBindings[$function] === []) {\n            return null;\n        }\n\n        $top = end(self::$callStackBindings[$function]);\n\n        return $top !== false ? $top : null;\n    }\n\n    private static function ensureInstanceInherited(object $instance): void\n    {\n        if (self::$instanceTemplateBindings === null || ! isset(self::$instanceTemplateBindings[$instance])) {\n            self::resolveInheritedTemplates($instance, $instance::class);\n        }\n    }\n\n    /**\n     * Checks if a symbol represents an existing class, interface, enum, or trait with fast non-autoloading cache.\n     */\n    private static function isRealTypeSymbol(string $name): bool\n    {\n        if (isset(self::$realTypeSymbolCache[$name])) {\n            return self::$realTypeSymbolCache[$name];\n        }\n\n        return self::$realTypeSymbolCache[$name] = class_exists($name, false)\n            || class_exists($name)\n            || interface_exists($name, false)\n            || interface_exists($name)\n            || enum_exists($name, false)\n            || enum_exists($name)\n            || trait_exists($name, false)\n            || trait_exists($name);\n    }\n\n    /**\n     * Resolves FQCNs inside an inherited generic TypeNode AST.\n     *\n     * @param \\ReflectionClass<object> $ref\n     */\n    private static function resolveTypeNodeAst(TypeNode $n, \\ReflectionClass $ref): TypeNode\n    {\n        if ($n instanceof IdentifierTypeNode) {\n            $lower = strtolower($n->name);\n            if ($lower === 'self' || $lower === 'static' || $lower === '$this') {\n                return new IdentifierTypeNode($ref->getName());\n            }\n\n            if ($lower === 'parent') {\n                $parent = $ref->getParentClass();\n\n                return new IdentifierTypeNode($parent !== false ? $parent->getName() : 'parent');\n            }\n\n            return new IdentifierTypeNode(SpecialTypeResolver::resolveFqcn($n->name, $ref));\n        }\n\n        if ($n instanceof GenericTypeNode) {\n            $lower = strtolower($n->type->name);\n            $baseName = match ($lower) {\n                'self', 'static', '$this' => $ref->getName(),\n                'parent' => ($parent = $ref->getParentClass()) !== false ? $parent->getName() : 'parent',\n                default => SpecialTypeResolver::resolveFqcn($n->type->name, $ref),\n            };\n\n            $base = new IdentifierTypeNode($baseName);\n            $generics = array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->genericTypes);\n\n            return new GenericTypeNode($base, $generics, $n->variances);\n        }\n\n        if ($n instanceof ArrayTypeNode) {\n            return new ArrayTypeNode(self::resolveTypeNodeAst($n->type, $ref));\n        }\n\n        if ($n instanceof NullableTypeNode) {\n            return new NullableTypeNode(self::resolveTypeNodeAst($n->type, $ref));\n        }\n\n        if ($n instanceof UnionTypeNode) {\n            return new UnionTypeNode(array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->types));\n        }\n\n        if ($n instanceof IntersectionTypeNode) {\n            return new IntersectionTypeNode(array_map(fn ($t) => self::resolveTypeNodeAst($t, $ref), $n->types));\n        }\n\n        return $n;\n    }\n}\n","/typephp/src/Internal/Generics/TemplateSubstitutor.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Generics;\n\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\n\n/**\n * @internal Recursively substitutes template placeholders (like T) with their bound concrete types (like int).\n */\nfinal class TemplateSubstitutor\n{\n    /**\n     * Recursively substitutes template placeholders (like T) with their bound concrete types (like int).\n     *\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     */\n    public static function substitute(TypeNode $node, array $boundTemplates, array $declaredTemplates = []): TypeNode\n    {\n        if (\\count($boundTemplates) === 0 && \\count($declaredTemplates) === 0) {\n            return $node;\n        }\n\n        return self::substituteNode($node, $boundTemplates, $declaredTemplates, []);\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteNode(\n        TypeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): TypeNode {\n        if ($node instanceof IdentifierTypeNode) {\n            return self::substituteIdentifier($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            return self::substituteCallable($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof ConditionalTypeNode) {\n            return self::substituteConditional($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof ConditionalTypeForParameterNode) {\n            return self::substituteParameterConditional($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof ArrayTypeNode) {\n            return new ArrayTypeNode(self::substituteNode($node->type, $boundTemplates, $declaredTemplates, $visited));\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            return self::substituteGeneric($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return new NullableTypeNode(self::substituteNode($node->type, $boundTemplates, $declaredTemplates, $visited));\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            return new UnionTypeNode(array_map(\n                fn ($t) => self::substituteNode($t, $boundTemplates, $declaredTemplates, $visited),\n                $node->types\n            ));\n        }\n\n        if ($node instanceof IntersectionTypeNode) {\n            return new IntersectionTypeNode(array_map(\n                fn ($t) => self::substituteNode($t, $boundTemplates, $declaredTemplates, $visited),\n                $node->types\n            ));\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            return self::substituteArrayShape($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            return self::substituteObjectShape($node, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        return $node;\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteIdentifier(\n        IdentifierTypeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): TypeNode {\n        if (isset($boundTemplates[$node->name])) {\n            return $boundTemplates[$node->name];\n        }\n\n        if (isset($declaredTemplates[$node->name])) {\n            if (isset($visited[$node->name])) {\n                return new IdentifierTypeNode('mixed');\n            }\n            $visited[$node->name] = true;\n\n            $templateTag = $declaredTemplates[$node->name];\n            $fallback = $templateTag->default ?? $templateTag->bound ?? new IdentifierTypeNode('mixed');\n\n            return self::substituteNode($fallback, $boundTemplates, $declaredTemplates, $visited);\n        }\n\n        return $node;\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteCallable(\n        CallableTypeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): CallableTypeNode {\n        $parameters = array_map(\n            fn (CallableTypeParameterNode $param) => new CallableTypeParameterNode(\n                self::substituteNode($param->type, $boundTemplates, $declaredTemplates, $visited),\n                $param->isReference,\n                $param->isVariadic,\n                $param->parameterName,\n                $param->isOptional\n            ),\n            $node->parameters\n        );\n\n        $returnType = self::substituteNode($node->returnType, $boundTemplates, $declaredTemplates, $visited);\n\n        return new CallableTypeNode(\n            $node->identifier,\n            $parameters,\n            $returnType,\n            $node->templateTypes\n        );\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteConditional(\n        ConditionalTypeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): ConditionalTypeNode {\n        return new ConditionalTypeNode(\n            self::substituteNode($node->subjectType, $boundTemplates, $declaredTemplates, $visited),\n            self::substituteNode($node->targetType, $boundTemplates, $declaredTemplates, $visited),\n            self::substituteNode($node->if, $boundTemplates, $declaredTemplates, $visited),\n            self::substituteNode($node->else, $boundTemplates, $declaredTemplates, $visited),\n            $node->negated\n        );\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteParameterConditional(\n        ConditionalTypeForParameterNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): ConditionalTypeForParameterNode {\n        return new ConditionalTypeForParameterNode(\n            $node->parameterName,\n            self::substituteNode($node->targetType, $boundTemplates, $declaredTemplates, $visited),\n            self::substituteNode($node->if, $boundTemplates, $declaredTemplates, $visited),\n            self::substituteNode($node->else, $boundTemplates, $declaredTemplates, $visited),\n            $node->negated\n        );\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteGeneric(\n        GenericTypeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): GenericTypeNode {\n        $type = self::substituteNode($node->type, $boundTemplates, $declaredTemplates, $visited);\n        $genericTypes = array_map(\n            fn ($t) => self::substituteNode($t, $boundTemplates, $declaredTemplates, $visited),\n            $node->genericTypes\n        );\n\n        return new GenericTypeNode(\n            $type instanceof IdentifierTypeNode ? $type : $node->type,\n            $genericTypes,\n            $node->variances\n        );\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteArrayShape(\n        ArrayShapeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): ArrayShapeNode {\n        $newItems = [];\n        foreach ($node->items as $item) {\n            $newItems[] = new ArrayShapeItemNode(\n                $item->keyName,\n                $item->optional,\n                self::substituteNode($item->valueType, $boundTemplates, $declaredTemplates, $visited)\n            );\n        }\n\n        $newUnsealed = null;\n        if ($node->unsealedType !== null) {\n            $unsealedKey = $node->unsealedType->keyType !== null\n                ? self::substituteNode($node->unsealedType->keyType, $boundTemplates, $declaredTemplates, $visited)\n                : null;\n            $unsealedVal = self::substituteNode($node->unsealedType->valueType, $boundTemplates, $declaredTemplates, $visited);\n            $newUnsealed = new ArrayShapeUnsealedTypeNode($unsealedVal, $unsealedKey);\n        }\n\n        if ($node->sealed) {\n            return ArrayShapeNode::createSealed($newItems, $node->kind);\n        }\n\n        return ArrayShapeNode::createUnsealed($newItems, $newUnsealed, $node->kind);\n    }\n\n    /**\n     * @param array<string, TypeNode> $boundTemplates\n     * @param array<string, TemplateTagValueNode> $declaredTemplates\n     * @param array<string, true> $visited\n     */\n    private static function substituteObjectShape(\n        ObjectShapeNode $node,\n        array $boundTemplates,\n        array $declaredTemplates,\n        array $visited\n    ): ObjectShapeNode {\n        $newItems = [];\n        foreach ($node->items as $item) {\n            $newItems[] = new ObjectShapeItemNode(\n                $item->keyName,\n                $item->optional,\n                self::substituteNode($item->valueType, $boundTemplates, $declaredTemplates, $visited)\n            );\n        }\n\n        return new ObjectShapeNode($newItems);\n    }\n}\n","/typephp/src/Internal/Io/CacheManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Io;\n\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\FileFilter;\n\n/**\n * @internal\n */\nfinal class CacheManager\n{\n    /**\n     * Cache version prefix string. Bump this whenever AST printer/transformation rules change.\n     */\n    public const VERSION_PREFIX = 'v0.1_';\n\n    /**\n     * Cached absolute cache directory path.\n     */\n    private static ?string $resolvedCacheDir = null;\n\n    /**\n     * Memoized verification state of the cache directory.\n     */\n    private static ?bool $secureDirVerified = null;\n\n    public static function reset(): void\n    {\n        self::$resolvedCacheDir = null;\n        self::$secureDirVerified = null;\n    }\n\n    /**\n     * Returns the absolute path to the cache directory, isolating by system user if using temp dir.\n     */\n    public static function getCacheDir(): string\n    {\n        if (self::$resolvedCacheDir !== null) {\n            return self::$resolvedCacheDir;\n        }\n\n        $config = Config::get();\n        $dir = $config['cache_dir'] ?? null;\n\n        if (\\is_string($dir) && $dir !== '') {\n            return self::$resolvedCacheDir = $dir;\n        }\n\n        $username = getenv('USERNAME');\n        $userEnv = getenv('USER');\n\n        if (\\function_exists('posix_geteuid')) {\n            $user = (string) posix_geteuid();\n        } elseif (\\is_string($username) && $username !== '') {\n            $user = $username;\n        } elseif (\\is_string($userEnv) && $userEnv !== '') {\n            $user = $userEnv;\n        } else {\n            $user = (string) getmyuid();\n        }\n\n        $userHash = hash('xxh128', 'typephp_' . $user);\n\n        return self::$resolvedCacheDir = sys_get_temp_dir() . '/typephp-cache-' . $userHash;\n    }\n\n    /**\n     * Generates a unique cache key for a given file path based on its mtime and version prefix.\n     */\n    public static function getCacheKey(string $resolvedPath): string\n    {\n        if (Config::isCacheCheckMtimeEnabled()) {\n            $mtime = @filemtime($resolvedPath);\n            $mtimeStr = $mtime !== false ? (string) $mtime : '0';\n\n            return hash('xxh128', self::VERSION_PREFIX . $resolvedPath . $mtimeStr);\n        }\n\n        return hash('xxh128', self::VERSION_PREFIX . $resolvedPath);\n    }\n\n    /**\n     * Returns the full absolute disk path to the cached transformed PHP file.\n     */\n    public static function getCachedFilePath(string $resolvedPath): string\n    {\n        return self::getCacheDir() . '/' . self::getCacheKey($resolvedPath) . '.php';\n    }\n\n    /**\n     * Ensures the cache directory exists securely.\n     * Enforces strict UID/0700 checks on system temp dirs, while allowing\n     * standard application permissions on custom user-configured directories.\n     */\n    public static function ensureSecureCacheDir(): bool\n    {\n        if (self::$secureDirVerified !== null) {\n            return self::$secureDirVerified;\n        }\n\n        $cacheDir = self::getCacheDir();\n\n        if (is_link($cacheDir)) {\n            return self::$secureDirVerified = false;\n        }\n\n        $config = Config::get();\n        $isCustomDir = \\is_string($config['cache_dir'] ?? null) && $config['cache_dir'] !== '';\n\n        if (! is_dir($cacheDir)) {\n            $mode = $isCustomDir ? 0775 : 0700;\n            if (! @mkdir($cacheDir, $mode, recursive: true) && ! is_dir($cacheDir)) {\n                return self::$secureDirVerified = false;\n            }\n            if (! $isCustomDir) {\n                @chmod($cacheDir, 0700);\n            }\n        }\n\n        if (! $isCustomDir && \\function_exists('posix_geteuid')) {\n            $owner = @fileowner($cacheDir);\n            if ($owner !== false && $owner !== posix_geteuid()) {\n                return self::$secureDirVerified = false;\n            }\n        }\n\n        return self::$secureDirVerified = is_writable($cacheDir);\n    }\n\n    /**\n     * Safely writes cached content atomically to avoid corruption or partial reads.\n     */\n    public static function writeCachedFileSafely(string $cachedFile, string $transformed): bool\n    {\n        if (! self::ensureSecureCacheDir()) {\n            return false;\n        }\n\n        $config = Config::get();\n        $isCustomDir = \\is_string($config['cache_dir'] ?? null) && $config['cache_dir'] !== '';\n\n        $cacheDir = \\dirname($cachedFile);\n        $tmpFile = $cacheDir . '/.tmp_' . bin2hex(random_bytes(8));\n\n        if (@file_put_contents($tmpFile, $transformed) === false) {\n            return false;\n        }\n\n        @chmod($tmpFile, $isCustomDir ? 0664 : 0600);\n\n        if (! @rename($tmpFile, $cachedFile)) {\n            @unlink($tmpFile);\n\n            return false;\n        }\n\n        return true;\n    }\n\n    /**\n     * Clears all cached transformed files from the cache directory.\n     */\n    public static function clear(): int\n    {\n        $config = Config::get();\n        $customDir = $config['cache_dir'] ?? null;\n\n        $dirsToClear = [];\n\n        if (\\is_string($customDir) && $customDir !== '') {\n            if (is_dir($customDir) && ! is_link($customDir)) {\n                $dirsToClear[] = $customDir;\n            }\n        } else {\n            $tempBase = sys_get_temp_dir();\n            $matchedDirs = glob($tempBase . '/typephp-cache-*');\n\n            if ($matchedDirs !== false) {\n                foreach ($matchedDirs as $d) {\n                    if (is_dir($d) && ! is_link($d)) {\n                        if (\\function_exists('posix_geteuid')) {\n                            $owner = @fileowner($d);\n                            if ($owner !== false && $owner !== posix_geteuid()) {\n                                continue;\n                            }\n                        }\n                        $dirsToClear[] = $d;\n                    }\n                }\n            }\n        }\n\n        $count = 0;\n        foreach ($dirsToClear as $dir) {\n            $files = glob($dir . '/*.php');\n            if ($files !== false) {\n                foreach ($files as $file) {\n                    if (is_file($file) && ! is_link($file)) {\n                        @unlink($file);\n                        $count++;\n                    }\n                }\n            }\n\n            $tmpFiles = glob($dir . '/.tmp_*');\n            if ($tmpFiles !== false) {\n                foreach ($tmpFiles as $tFile) {\n                    if (is_file($tFile) && ! is_link($tFile)) {\n                        @unlink($tFile);\n                    }\n                }\n            }\n        }\n\n        return $count;\n    }\n\n    /**\n     * Recursively scans and pre-transforms all PHP files matching configured include patterns.\n     *\n     * @param (callable(string $status, string $file, int $current, int $total): void)|null $progressCallback\n     *\n     * @return array{total: int, cached: int, skipped: int}\n     */\n    public static function warmUp(?callable $progressCallback = null): array\n    {\n        $config = Config::get();\n        if (! (bool) ($config['enabled'] ?? true)) {\n            return ['total' => 0, 'cached' => 0, 'skipped' => 0];\n        }\n\n        $cwd = getcwd();\n        $baseDir = $cwd !== false ? rtrim(str_replace('\\\\', '/', $cwd), '/') : '';\n\n        $files = self::findFilesToWarm($baseDir);\n        $total = \\count($files);\n        $cached = 0;\n        $skipped = 0;\n\n        foreach ($files as $idx => $file) {\n            $cachedFile = self::getCachedFilePath($file);\n\n            if (! file_exists($cachedFile)) {\n                $source = file_get_contents($file);\n                if ($source !== false) {\n                    $transformed = StreamWrapper::transformSource($source, $file);\n                    if (self::writeCachedFileSafely($cachedFile, $transformed)) {\n                        $cached++;\n                    }\n                    if ($progressCallback !== null) {\n                        $progressCallback('cached', $file, $idx + 1, $total);\n                    }\n                }\n            } else {\n                $skipped++;\n                if ($progressCallback !== null) {\n                    $progressCallback('skipped', $file, $idx + 1, $total);\n                }\n            }\n        }\n\n        return [\n            'total' => $total,\n            'cached' => $cached,\n            'skipped' => $skipped,\n        ];\n    }\n\n    /**\n     * Scans base directory for non-excluded .php files.\n     *\n     * @return array<int, string>\n     */\n    private static function findFilesToWarm(string $baseDir): array\n    {\n        if ($baseDir === '' || ! is_dir($baseDir)) {\n            return [];\n        }\n\n        $files = [];\n\n        try {\n            $iterator = new \\RecursiveIteratorIterator(\n                new \\RecursiveDirectoryIterator($baseDir, \\FilesystemIterator::SKIP_DOTS | \\FilesystemIterator::FOLLOW_SYMLINKS)\n            );\n\n            foreach ($iterator as $fileInfo) {\n                if ($fileInfo instanceof \\SplFileInfo && $fileInfo->isFile() && strtolower($fileInfo->getExtension()) === 'php') {\n                    $realPath = $fileInfo->getRealPath();\n                    if ($realPath !== false) {\n                        $path = str_replace('\\\\', '/', $realPath);\n                        if (! FileFilter::isFileExcluded($path)) {\n                            $files[] = $path;\n                        }\n                    }\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently handle filesystem read errors\n        }\n\n        return $files;\n    }\n}\n","/typephp/src/Internal/Io/StreamWrapper.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Io;\n\nrequire_once __DIR__ . '/../Util/PathMatcher.php';\n\nuse PhpParser\\NodeTraverser;\nuse PhpParser\\NodeVisitor\\CloningVisitor;\nuse PhpParser\\Parser;\nuse PhpParser\\ParserFactory;\nuse TypePHP\\Internal\\Ast\\ContractVisitor;\nuse TypePHP\\Internal\\Ast\\TypePHPPrinter;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\IgnoreManager;\nuse TypePHP\\Internal\\Util\\PathMatcher;\n\n/**\n * Intercepts PHP 'file://' protocol operations to perform on-the-fly AST transformations\n * on included application source files while bypassing non-application paths and read-only inspections.\n *\n * @internal\n */\nfinal class StreamWrapper implements StreamWrapperInterface\n{\n    /**\n     * Bitmask constant passed by PHP's Zend Engine when a stream is opened by include or require.\n     */\n    public const STREAM_OPEN_FOR_INCLUDE = 128;\n\n    /**\n     * Context resource provided by PHP stream subsystem.\n     *\n     * @var resource|null\n     */\n    public $context;\n\n    /**\n     * @var resource|null\n     */\n    private $handle = null;\n\n    /**\n     * @var resource|null\n     */\n    private $dirHandle = null;\n\n    private static bool $isRegistered = false;\n\n    private static bool $cacheEnabled = true;\n\n    /**\n     * Reusable AST parser singleton.\n     */\n    private static ?Parser $parser = null;\n\n    /**\n     * Reusable AST printer singleton.\n     */\n    private static ?TypePHPPrinter $printer = null;\n\n    /**\n     * Reusable AST cloning visitor singleton.\n     */\n    private static ?CloningVisitor $cloningVisitor = null;\n\n    /**\n     * In-memory cache for positive url_stat results.\n     *\n     * @var array<string, array<int|string, int>>\n     */\n    private static array $statCache = [];\n\n    /**\n     * In-memory cache for static-path negative misses only (vendor & package source directories).\n     *\n     * @var array<string, true>\n     */\n    private static array $staticNegativeStatCache = [];\n\n    /**\n     * In-memory cache for isApplicationFile path decisions.\n     *\n     * @var array<string, bool>\n     */\n    private static array $appFileDecisionCache = [];\n\n    /**\n     * Native PHP functions that read raw source code for viewing, highlighting, or tokenizing.\n     *\n     * @var array<string, true>\n     */\n    private const READ_ONLY_FUNCTIONS = [\n        'file_get_contents' => true,\n        'file' => true,\n        'readfile' => true,\n        'highlight_file' => true,\n        'show_source' => true,\n        'token_get_all' => true,\n    ];\n\n    /**\n     * Returns a shared singleton instance of the PHP-Parser parser.\n     */\n    public static function getParser(): Parser\n    {\n        return self::$parser ??= (new ParserFactory())->createForNewestSupportedVersion();\n    }\n\n    /**\n     * Returns a shared singleton instance of the TypePHP format-preserving printer.\n     */\n    public static function getPrinter(): TypePHPPrinter\n    {\n        return self::$printer ??= new TypePHPPrinter();\n    }\n\n    /**\n     * Returns a shared singleton instance of the AST CloningVisitor.\n     */\n    public static function getCloningVisitor(): CloningVisitor\n    {\n        return self::$cloningVisitor ??= new CloningVisitor();\n    }\n\n    /**\n     * Resets all internal in-memory caches and path matchers.\n     */\n    public static function reset(): void\n    {\n        self::$statCache = [];\n        self::$staticNegativeStatCache = [];\n        self::$appFileDecisionCache = [];\n        PathMatcher::reset();\n    }\n\n    /**\n     * Registers the stream wrapper for the native 'file://' protocol.\n     *\n     * @param array<string, mixed> $config\n     */\n    public static function register(array $config = []): void\n    {\n        $resolvedConfig = array_replace_recursive(Config::get(), $config);\n\n        self::$cacheEnabled = (bool) ($resolvedConfig['cache'] ?? true);\n\n        if (! self::$isRegistered) {\n            stream_wrapper_unregister('file');\n            stream_wrapper_register('file', self::class);\n            self::$isRegistered = true;\n        }\n    }\n\n    /**\n     * Returns whether the stream wrapper is currently registered.\n     */\n    public static function isRegistered(): bool\n    {\n        return self::$isRegistered;\n    }\n\n    /**\n     * Restores PHP's native 'file://' stream wrapper handler.\n     */\n    public static function unregister(): void\n    {\n        if (self::$isRegistered) {\n            @stream_wrapper_restore('file');\n            self::$isRegistered = false;\n        }\n    }\n\n    /**\n     * Transforms PHP source code by parsing AST, extracting metadata, applying ContractVisitor,\n     * and formatting output while preserving exact line numbers to prevent line-drift in debug stack traces.\n     */\n    public static function transformSource(string $source, string $filePath = ''): string\n    {\n        if (str_contains($source, '@typephp-ignore-file') || str_contains($source, '@typephp-disable-file')) {\n            if ($filePath !== '') {\n                IgnoreManager::registerIgnoredFile($filePath);\n            }\n\n            if (Config::isRespectIgnoreTagsEnabled()) {\n                return $source;\n            }\n        }\n\n        $originalLineCount = substr_count($source, \"\\n\");\n\n        $parser = self::getParser();\n\n        try {\n            $oldStmts = $parser->parse($source);\n            if ($oldStmts === null) {\n                return $source;\n            }\n        } catch (\\Throwable $e) {\n            return $source;\n        }\n\n        self::extractAndSeedFileMetadata($oldStmts, $filePath);\n\n        $oldTokens = $parser->getTokens();\n\n        $traverser1 = new NodeTraverser();\n        $traverser1->addVisitor(self::getCloningVisitor());\n\n        /** @var array<\\PhpParser\\Node\\Stmt> $nodesToTraverse */\n        $nodesToTraverse = $oldStmts;\n        $newStmts = $traverser1->traverse($nodesToTraverse);\n\n        $traverser2 = new NodeTraverser();\n        $traverser2->addVisitor(new ContractVisitor());\n        $newStmts = $traverser2->traverse($newStmts);\n\n        $printer = self::getPrinter();\n        $transformed = $printer->printFormatPreserving($newStmts, $oldStmts, $oldTokens);\n\n        $transformed = self::neutralizeTrailingLineComments($transformed);\n        $transformed = preg_replace('/[ \\t]*\\r?\\n[ \\t]*\\/\\*__TYPEPHP_INJECTED_START__\\*\\//', ' /*__TYPEPHP_INJECTED_START__*/', $transformed) ?? $transformed;\n\n        $transformedLineCount = substr_count($transformed, \"\\n\");\n        $drift = $transformedLineCount - $originalLineCount;\n        $count1 = 0;\n        $count2 = 0;\n\n        if ($drift > 0) {\n            $transformed = preg_replace('/[ \\t]*\\r?\\n[ \\t]*\\{[ \\t]*\\/\\*__TYPEPHP_INJECTED_START__\\*\\//', ' { /*__TYPEPHP_INJECTED_START__*/', $transformed, $drift, $count1) ?? $transformed;\n            $drift -= $count1;\n        }\n\n        if ($drift > 0) {\n            $transformed = preg_replace('/\\/\\*__TYPEPHP_INJECTED_END__\\*\\/[ \\t]*\\r?\\n[ \\t]*\\}/', '/*__TYPEPHP_INJECTED_END__*/ }', $transformed, $drift, $count2) ?? $transformed;\n            $drift -= $count2;\n        }\n\n        if ($drift > 0) {\n            $transformed = preg_replace('/\\/\\*__TYPEPHP_INJECTED_END__\\*\\/[ \\t]*\\r?\\n[ \\t]*/', '/*__TYPEPHP_INJECTED_END__*/ ', $transformed, $drift) ?? $transformed;\n        }\n\n        return str_replace(['/*__TYPEPHP_INJECTED_START__*/', '/*__TYPEPHP_INJECTED_END__*/'], '', $transformed);\n    }\n\n    /**\n     * Safely neutralises trailing single-line comments (// or #) preceding an injected check\n     * into block comments without corrupting string literals containing '//' or '#'.\n     */\n    private static function neutralizeTrailingLineComments(string $code): string\n    {\n        if (! str_contains($code, '/*__TYPEPHP_INJECTED_START__*/')) {\n            return $code;\n        }\n\n        try {\n            $tokens = \\PhpToken::tokenize($code);\n            $count = \\count($tokens);\n            $result = '';\n\n            for ($i = 0; $i < $count; $i++) {\n                $token = $tokens[$i];\n\n                if ($token->id === T_COMMENT && (str_starts_with($token->text, '//') || str_starts_with($token->text, '#'))) {\n                    $isPrecedingInjection = false;\n\n                    for ($j = $i + 1; $j < $count; $j++) {\n                        $next = $tokens[$j];\n                        if ($next->id === T_WHITESPACE) {\n                            continue;\n                        }\n                        if ($next->id === T_COMMENT && str_starts_with($next->text, '/*__TYPEPHP_INJECTED_START__*/')) {\n                            $isPrecedingInjection = true;\n                        }\n\n                        break;\n                    }\n\n                    if ($isPrecedingInjection) {\n                        $commentText = rtrim($token->text, \"\\r\\n\");\n                        $trailingNewlines = substr($token->text, \\strlen($commentText));\n                        $cleaned = ltrim($commentText, '/# ');\n                        $result .= '/* ' . $cleaned . ' */' . $trailingNewlines;\n\n                        continue;\n                    }\n                }\n\n                $result .= $token->text;\n            }\n\n            return $result;\n        } catch (\\Throwable $e) {\n            return $code;\n        }\n    }\n\n    /**\n     * Opens a file stream using a multi-stage validation pipeline:\n     * 1. Rejects non-include operations, non-read modes, and non-PHP files directly.\n     * 2. Runs high-speed string prefix pre-filtering to bypass excluded vendor, cache, and storage paths.\n     * 3. Detects native source-viewing functions (error screen highlighters and tokenizers) to serve raw source code.\n     * 4. Executes a single unregister/register block for application files to load cached or memory-transformed bytecode.\n     */\n    public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool\n    {\n        $isInclude = ($options & self::STREAM_OPEN_FOR_INCLUDE) !== 0;\n\n        if (! $isInclude || ($mode !== 'r' && $mode !== 'rb' && $mode !== 'rt') || ! str_ends_with(strtolower($path), '.php') || ! Config::isEnabled()) {\n            return $this->openDirectHandle($path, $mode, $options);\n        }\n\n        $normalizedRaw = str_replace('\\\\', '/', $path);\n        if (! PathMatcher::mayPathBeIncluded($normalizedRaw)) {\n            return $this->openDirectHandle($path, $mode, $options);\n        }\n\n        if (self::isReadOnlyCall()) {\n            return $this->openDirectHandle($path, $mode, $options);\n        }\n\n        self::unregister();\n\n        $exists = (bool) self::silent(static fn () => file_exists($path));\n        $resolvedPath = $exists ? self::silent(static fn () => realpath($path)) : false;\n\n        if (! $exists || $resolvedPath === false || ! self::isApplicationFile($path, $resolvedPath)) {\n            $target = ($resolvedPath !== false) ? $resolvedPath : $path;\n            /** @var resource|false $handle */\n            $handle = self::silent(\n                fn () => ($this->context !== null)\n                    ? fopen($target, $mode, false, $this->context)\n                    : fopen($target, $mode)\n            );\n            $this->handle = $handle !== false ? $handle : null;\n            self::register();\n\n            return $this->handle !== null;\n        }\n\n        $success = self::$cacheEnabled\n            ? $this->openCachedStream($resolvedPath, $mode)\n            : $this->openMemoryStream($resolvedPath);\n\n        self::register();\n\n        return $success;\n    }\n\n    /**\n     * Determines whether the stream is being opened by a native PHP source-viewing function\n     * (e.g. highlight_file, show_source, file_get_contents, token_get_all) by inspecting shallow backtrace frames.\n     */\n    private static function isReadOnlyCall(): bool\n    {\n        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);\n\n        $caller1 = strtolower($trace[1]['function'] ?? '');\n        $caller2 = strtolower($trace[2]['function'] ?? '');\n\n        return isset(self::READ_ONLY_FUNCTIONS[$caller1]) || isset(self::READ_ONLY_FUNCTIONS[$caller2]);\n    }\n\n    /**\n     * Opens an underlying filesystem handle directly with error reporting options and context support.\n     */\n    private function openDirectHandle(string $targetFile, string $mode, int $options): bool\n    {\n        $isInclude = ($options & self::STREAM_OPEN_FOR_INCLUDE) !== 0;\n        $useIncludePath = ($options & STREAM_USE_PATH) !== 0;\n\n        self::unregister();\n        /** @var resource|false $handle */\n        $handle = self::silent(\n            fn () => ($this->context !== null)\n                ? fopen($targetFile, $mode, $useIncludePath, $this->context)\n                : fopen($targetFile, $mode, $useIncludePath)\n        );\n        $this->handle = $handle !== false ? $handle : null;\n        self::register();\n\n        if ($this->handle === null && ! $isInclude) {\n            trigger_error(\"fopen({$targetFile}): Failed to open stream: No such file or directory\", E_USER_WARNING);\n        }\n\n        return $this->handle !== null;\n    }\n\n    public function stream_read(int $count): string\n    {\n        if ($this->handle === null || $count <= 0) {\n            return '';\n        }\n\n        $res = fread($this->handle, $count);\n\n        return $res !== false ? $res : '';\n    }\n\n    public function stream_write(string $data): int\n    {\n        if ($this->handle === null) {\n            return 0;\n        }\n\n        $res = fwrite($this->handle, $data);\n\n        return $res !== false ? $res : 0;\n    }\n\n    public function stream_lock(int $operation): bool\n    {\n        if ($this->handle === null) {\n            return false;\n        }\n\n        if ($operation < 1 || $operation > 15) {\n            return true;\n        }\n\n        // @phpstan-ignore argument.type\n        return @flock($this->handle, $operation);\n    }\n\n    public function stream_tell(): int\n    {\n        if ($this->handle === null) {\n            return 0;\n        }\n\n        $res = ftell($this->handle);\n\n        return $res !== false ? $res : 0;\n    }\n\n    public function stream_flush(): bool\n    {\n        if ($this->handle === null) {\n            return false;\n        }\n\n        return fflush($this->handle);\n    }\n\n    public function stream_truncate(int $new_size): bool\n    {\n        if ($this->handle === null || $new_size < 0) {\n            return false;\n        }\n\n        return ftruncate($this->handle, $new_size);\n    }\n\n    public function stream_eof(): bool\n    {\n        if ($this->handle === null) {\n            return true;\n        }\n\n        return feof($this->handle);\n    }\n\n    /**\n     * @return array<int|string, int>|false\n     */\n    public function stream_stat(): array|false\n    {\n        if ($this->handle === null) {\n            return false;\n        }\n\n        return fstat($this->handle);\n    }\n\n    /**\n     * Extracts the underlying native file descriptor for C-level functions like proc_open or stream_select.\n     *\n     * @return resource|false\n     */\n    public function stream_cast(int $cast_as)\n    {\n        return $this->handle !== null ? $this->handle : false;\n    }\n\n    public function stream_seek(int $offset, int $whence = SEEK_SET): bool\n    {\n        if ($this->handle === null) {\n            return false;\n        }\n\n        return @fseek($this->handle, $offset, $whence) === 0;\n    }\n\n    public function stream_set_option(int $option, int $arg1, int $arg2): bool\n    {\n        return false;\n    }\n\n    public function stream_close(): void\n    {\n        if ($this->handle !== null) {\n            fclose($this->handle);\n            $this->handle = null;\n        }\n    }\n\n    /**\n     * Resolves file status with dual-tier memoization caching:\n     * 1. Differentiates between stat() and lstat() (STREAM_URL_STAT_LINK).\n     * 2. Memoizes PHP files, vendor files, and static package source directories.\n     *\n     * NOTE: stat() and lstat() DO trigger recursive url_stat calls when the\n     * file:// wrapper is registered. The unregister/register cycle is REQUIRED.\n     *\n     * @return array<int|string, int>|false\n     */\n    public function url_stat(string $path, int $flags): array|false\n    {\n        $normalized = str_replace('\\\\', '/', $path);\n        $isLink = ($flags & STREAM_URL_STAT_LINK) !== 0;\n        $cacheKey = $normalized . ($isLink ? ':lstat' : ':stat');\n\n        if (isset(self::$statCache[$cacheKey])) {\n            return self::$statCache[$cacheKey];\n        }\n\n        if (isset(self::$staticNegativeStatCache[$normalized])) {\n            return false;\n        }\n\n        self::unregister();\n        /** @var array<int|string, int>|false $result */\n        $result = self::silent(static fn () => $isLink ? @lstat($path) : @stat($path));\n        self::register();\n\n        if ($result !== false) {\n            $isPhp = str_ends_with(strtolower($normalized), '.php');\n            $isStaticDir = is_dir($path) && PathMatcher::isStaticSourcePath($normalized);\n\n            if ($isPhp || PathMatcher::isVendorPath($normalized) || $isStaticDir) {\n                self::$statCache[$cacheKey] = $result;\n            }\n\n            return $result;\n        }\n\n        if (PathMatcher::isStaticSourcePath($normalized)) {\n            self::$staticNegativeStatCache[$normalized] = true;\n        }\n\n        return false;\n    }\n\n    public function stream_metadata(string $path, int $option, mixed $value): bool\n    {\n        $normalized = str_replace('\\\\', '/', $path);\n        unset(\n            self::$statCache[$normalized . ':stat'],\n            self::$statCache[$normalized . ':lstat'],\n            self::$staticNegativeStatCache[$normalized]\n        );\n\n        self::unregister();\n        $result = false;\n        if ($option === STREAM_META_TOUCH) {\n            /** @var array{0?: int, 1?: int} $valueArray */\n            $valueArray = \\is_array($value) ? $value : [];\n            $time = $valueArray[0] ?? time();\n            $atime = $valueArray[1] ?? $time;\n            $result = (bool) self::silent(fn () => @touch($path, (int) $time, (int) $atime));\n        } elseif ($option === STREAM_META_ACCESS) {\n            /** @var int $mode */\n            $mode = \\is_int($value) ? $value : 0777;\n            $result = (bool) self::silent(fn () => @chmod($path, $mode));\n        }\n        self::register();\n\n        return $result;\n    }\n\n    public function dir_opendir(string $path, int $options): bool\n    {\n        self::unregister();\n        /** @var resource|false $dh */\n        $dh = self::silent(\n            fn () => ($this->context !== null)\n                ? @opendir($path, $this->context)\n                : @opendir($path)\n        );\n        $this->dirHandle = $dh !== false ? $dh : null;\n        self::register();\n\n        return $this->dirHandle !== null;\n    }\n\n    public function dir_readdir(): string|false\n    {\n        if ($this->dirHandle === null) {\n            return false;\n        }\n\n        return readdir($this->dirHandle);\n    }\n\n    public function dir_rewinddir(): bool\n    {\n        if ($this->dirHandle === null) {\n            return false;\n        }\n\n        rewinddir($this->dirHandle);\n\n        return true;\n    }\n\n    public function dir_closedir(): bool\n    {\n        if ($this->dirHandle !== null) {\n            closedir($this->dirHandle);\n            $this->dirHandle = null;\n        }\n\n        return true;\n    }\n\n    public function mkdir(string $path, int $mode, int $options): bool\n    {\n        $normalized = str_replace('\\\\', '/', $path);\n        unset(\n            self::$statCache[$normalized . ':stat'],\n            self::$statCache[$normalized . ':lstat'],\n            self::$staticNegativeStatCache[$normalized]\n        );\n\n        self::unregister();\n        $result = ($this->context !== null)\n            ? @mkdir($path, $mode, ($options & STREAM_MKDIR_RECURSIVE) !== 0, $this->context)\n            : @mkdir($path, $mode, ($options & STREAM_MKDIR_RECURSIVE) !== 0);\n        self::register();\n\n        return $result;\n    }\n\n    public function rmdir(string $path, int $options): bool\n    {\n        $normalized = str_replace('\\\\', '/', $path);\n        unset(\n            self::$statCache[$normalized . ':stat'],\n            self::$statCache[$normalized . ':lstat'],\n            self::$staticNegativeStatCache[$normalized]\n        );\n\n        self::unregister();\n        $result = ($this->context !== null)\n            ? rmdir($path, $this->context)\n            : rmdir($path);\n        self::register();\n\n        return $result;\n    }\n\n    public function unlink(string $path): bool\n    {\n        $normalized = str_replace('\\\\', '/', $path);\n        unset(\n            self::$statCache[$normalized . ':stat'],\n            self::$statCache[$normalized . ':lstat'],\n            self::$staticNegativeStatCache[$normalized]\n        );\n\n        self::unregister();\n        $result = ($this->context !== null)\n            ? unlink($path, $this->context)\n            : unlink($path);\n        self::register();\n\n        return $result;\n    }\n\n    public function rename(string $pathFrom, string $pathTo): bool\n    {\n        $normFrom = str_replace('\\\\', '/', $pathFrom);\n        $normTo = str_replace('\\\\', '/', $pathTo);\n        unset(\n            self::$statCache[$normFrom . ':stat'],\n            self::$statCache[$normFrom . ':lstat'],\n            self::$staticNegativeStatCache[$normFrom],\n            self::$statCache[$normTo . ':stat'],\n            self::$statCache[$normTo . ':lstat'],\n            self::$staticNegativeStatCache[$normTo]\n        );\n\n        self::unregister();\n        $result = ($this->context !== null)\n            ? rename($pathFrom, $pathTo, $this->context)\n            : rename($pathFrom, $pathTo);\n        self::register();\n\n        return $result;\n    }\n\n    /**\n     * Executes a callback while temporarily suppressing PHP error and warning handlers.\n     *\n     * @template T\n     *\n     * @param callable(): T $callback\n     *\n     * @return T\n     */\n    private static function silent(callable $callback): mixed\n    {\n        set_error_handler(static fn () => true);\n\n        try {\n            return $callback();\n        } finally {\n            restore_error_handler();\n        }\n    }\n\n    /**\n     * Determines whether a target PHP file path matches configured inclusion criteria and is not excluded.\n     */\n    private static function isApplicationFile(string $path, string|false $resolvedPath): bool\n    {\n        if (! Config::isEnabled()) {\n            return false;\n        }\n\n        if (! str_ends_with($path, '.php') || $resolvedPath === false) {\n            return false;\n        }\n\n        $normalizedPath = PathMatcher::normalizePath($resolvedPath);\n\n        if (isset(self::$appFileDecisionCache[$normalizedPath])) {\n            return self::$appFileDecisionCache[$normalizedPath];\n        }\n\n        if (PathMatcher::isLibraryInternal($normalizedPath)) {\n            return self::$appFileDecisionCache[$normalizedPath] = false;\n        }\n\n        if (PathMatcher::isCachePath($normalizedPath)) {\n            return self::$appFileDecisionCache[$normalizedPath] = false;\n        }\n\n        $config = Config::get();\n        /** @var array<int, string> $includes */\n        $includes = \\is_array($config['include'] ?? null) ? $config['include'] : ['**'];\n        /** @var array<int, string> $excludes */\n        $excludes = \\is_array($config['exclude'] ?? null) ? $config['exclude'] : ['vendor/**', 'storage/**', 'var/**', 'cache/**'];\n\n        $isIncluded = PathMatcher::isPathIncluded($normalizedPath, $includes, $excludes, $path);\n\n        return self::$appFileDecisionCache[$normalizedPath] = $isIncluded;\n    }\n\n    /**\n     * Transforms and loads source code in-memory via a RAM stream handle.\n     */\n    private function openMemoryStream(string $resolvedPath): bool\n    {\n        $source = file_get_contents($resolvedPath);\n        if ($source === false) {\n            return false;\n        }\n\n        $transformed = self::transformSource($source, $resolvedPath);\n\n        $memHandle = fopen('php://memory', 'r+');\n        if ($memHandle !== false) {\n            fwrite($memHandle, $transformed);\n            rewind($memHandle);\n            $this->handle = $memHandle;\n        }\n\n        return $this->handle !== null;\n    }\n\n    /**\n     * Transforms, persists, and loads cached source code from disk in a single handle open.\n     */\n    private function openCachedStream(string $resolvedPath, string $mode): bool\n    {\n        $cachedFile = CacheManager::getCachedFilePath($resolvedPath);\n\n        if (! CacheManager::ensureSecureCacheDir()) {\n            return $this->openMemoryStream($resolvedPath);\n        }\n\n        if (! file_exists($cachedFile) || is_link($cachedFile)) {\n            $source = file_get_contents($resolvedPath);\n            if ($source === false) {\n                return false;\n            }\n            $transformed = self::transformSource($source, $resolvedPath);\n            if (! CacheManager::writeCachedFileSafely($cachedFile, $transformed)) {\n                return $this->openMemoryStream($resolvedPath);\n            }\n        }\n\n        $cacheHandle = ($this->context !== null)\n            ? fopen($cachedFile, $mode, false, $this->context)\n            : fopen($cachedFile, $mode);\n        $this->handle = $cacheHandle !== false ? $cacheHandle : null;\n\n        return $this->handle !== null;\n    }\n\n    /**\n     * Scans top-level AST statements for namespace, use imports, and trait use declarations to seed SpecialTypeResolver.\n     *\n     * @param array<\\PhpParser\\Node\\Stmt> $stmts\n     */\n    private static function extractAndSeedFileMetadata(array $stmts, string $filePath): void\n    {\n        if ($filePath === '') {\n            return;\n        }\n\n        $namespace = '';\n        $imports = [];\n        $classTraitUseDocs = [];\n        $anonymousTraitUseDocs = [];\n\n        $nodesToScan = $stmts;\n        foreach ($stmts as $stmt) {\n            if ($stmt instanceof \\PhpParser\\Node\\Stmt\\Namespace_) {\n                $namespace = $stmt->name !== null ? $stmt->name->toString() : '';\n                $nodesToScan = $stmt->stmts;\n\n                break;\n            }\n        }\n\n        foreach ($nodesToScan as $stmt) {\n            if ($stmt instanceof \\PhpParser\\Node\\Stmt\\Use_) {\n                if ($stmt->type !== \\PhpParser\\Node\\Stmt\\Use_::TYPE_NORMAL) {\n                    continue;\n                }\n\n                foreach ($stmt->uses as $use) {\n                    $fqcn = $use->name->toString();\n                    $alias = $use->getAlias()->toString();\n                    $imports[$alias] = $fqcn;\n                }\n            } elseif ($stmt instanceof \\PhpParser\\Node\\Stmt\\GroupUse) {\n                $prefix = $stmt->prefix->toString();\n\n                foreach ($stmt->uses as $use) {\n                    if ($use->type !== \\PhpParser\\Node\\Stmt\\Use_::TYPE_NORMAL && $use->type !== \\PhpParser\\Node\\Stmt\\Use_::TYPE_UNKNOWN && $stmt->type !== \\PhpParser\\Node\\Stmt\\Use_::TYPE_NORMAL) {\n                        continue;\n                    }\n\n                    $fqcn = $prefix . '\\\\' . $use->name->toString();\n                    $alias = $use->getAlias()->toString();\n                    $imports[$alias] = $fqcn;\n                }\n            } elseif ($stmt instanceof \\PhpParser\\Node\\Stmt\\Class_ && $stmt->name !== null) {\n                $className = $namespace !== '' ? $namespace . '\\\\' . $stmt->name->toString() : $stmt->name->toString();\n                foreach ($stmt->stmts as $classStmt) {\n                    if ($classStmt instanceof \\PhpParser\\Node\\Stmt\\TraitUse) {\n                        $doc = $classStmt->getDocComment();\n                        if ($doc !== null) {\n                            $classTraitUseDocs[$className][] = $doc->getText();\n                        }\n                    }\n                }\n            }\n        }\n\n        $nodeFinder = new \\PhpParser\\NodeFinder();\n        /** @var list<\\PhpParser\\Node\\Stmt\\Class_> $anonClasses */\n        $anonClasses = $nodeFinder->find($stmts, function (\\PhpParser\\Node $node): bool {\n            return $node instanceof \\PhpParser\\Node\\Stmt\\Class_ && $node->name === null;\n        });\n\n        foreach ($anonClasses as $anonClass) {\n            $startLine = $anonClass->getStartLine();\n            foreach ($anonClass->stmts as $classStmt) {\n                if ($classStmt instanceof \\PhpParser\\Node\\Stmt\\TraitUse) {\n                    $doc = $classStmt->getDocComment();\n                    if ($doc !== null) {\n                        $anonymousTraitUseDocs[$startLine][] = $doc->getText();\n                    }\n                }\n            }\n        }\n\n        SpecialTypeResolver::seedFileMetadata($filePath, $namespace, $imports, $classTraitUseDocs, $anonymousTraitUseDocs);\n    }\n}\n","/typephp/src/Internal/Io/StreamWrapperInterface.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Io;\n\n/**\n * @internal Contract defining PHP's native stream wrapper protocol methods.\n *\n * @see https://www.php.net/manual/en/class.streamwrapper.php\n */\ninterface StreamWrapperInterface\n{\n    public function stream_open(string $path, string $mode, int $options, ?string &$openedPath): bool;\n\n    public function stream_read(int $count): string;\n\n    public function stream_write(string $data): int;\n\n    public function stream_lock(int $operation): bool;\n\n    public function stream_flush(): bool;\n\n    public function stream_truncate(int $new_size): bool;\n\n    public function stream_eof(): bool;\n\n    /**\n     * @return array<int|string, int>|false\n     */\n    public function stream_stat(): array|false;\n\n    public function stream_seek(int $offset, int $whence = SEEK_SET): bool;\n\n    public function stream_set_option(int $option, int $arg1, int $arg2): bool;\n\n    public function stream_close(): void;\n\n    /**\n     * @return array<int|string, int>|false\n     */\n    public function url_stat(string $path, int $flags): array|false;\n\n    public function dir_opendir(string $path, int $options): bool;\n\n    public function dir_readdir(): string|false;\n\n    public function dir_rewinddir(): bool;\n\n    public function dir_closedir(): bool;\n\n    public function mkdir(string $path, int $mode, int $options): bool;\n\n    public function rmdir(string $path, int $options): bool;\n\n    public function unlink(string $path): bool;\n\n    public function rename(string $pathFrom, string $pathTo): bool;\n\n    public function stream_metadata(string $path, int $option, mixed $value): bool;\n\n    /**\n     * @return resource|false\n     */\n    public function stream_cast(int $cast_as);\n\n    public function stream_tell(): int;\n}\n","/typephp/src/Internal/Resolver/CallerBoundaryResolver.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Resolver;\n\nuse Closure;\nuse ReflectionClass;\nuse ReflectionFunction;\nuse Throwable;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\PathMatcher;\n\n/**\n * @internal Resolves whether a type check failure should be bypassed because it occurred at a vendor-to-vendor boundary.\n */\nfinal class CallerBoundaryResolver\n{\n    /**\n     * @var array<string, bool> functionName => isCalleeVendor\n     */\n    private static array $calleeVendorCache = [];\n\n    /**\n     * @var array<string, bool> normalizedFilePath => isCallerVendor\n     */\n    private static array $callerVendorCache = [];\n\n    public static function reset(): void\n    {\n        self::$calleeVendorCache = [];\n        self::$callerVendorCache = [];\n    }\n\n    /**\n     * Determines whether a type check failure on a function/method should be bypassed.\n     * Only bypasses if the callee is located in a vendor path AND the caller is also from vendor.\n     */\n    public static function shouldBypass(string $function): bool\n    {\n        if (! Config::isVendorBoundaryOnlyEnabled()) {\n            return false;\n        }\n\n        if (! self::isCalleeVendor($function)) {\n            return false;\n        }\n\n        return self::isCallerVendor();\n    }\n\n    /**\n     * Determines whether a type check failure inside a wrapped callback/closure should be bypassed.\n     */\n    public static function shouldBypassCallback(mixed $callable, string $prefix = ''): bool\n    {\n        if (! Config::isVendorBoundaryOnlyEnabled()) {\n            return false;\n        }\n\n        if ($callable instanceof Closure) {\n            try {\n                $ref = new ReflectionFunction($callable);\n                $file = $ref->getFileName();\n                if ($file !== false && $file !== null) {\n                    $normalized = PathMatcher::normalizePath($file);\n\n                    return PathMatcher::isVendorPath($normalized);\n                }\n            } catch (Throwable $e) {\n            }\n        }\n\n        return self::isCallerVendor();\n    }\n\n    /**\n     * Checks if the function or method being executed belongs to a vendor file.\n     */\n    public static function isCalleeVendor(string $function): bool\n    {\n        if (isset(self::$calleeVendorCache[$function])) {\n            return self::$calleeVendorCache[$function];\n        }\n\n        $fileName = null;\n\n        try {\n            if (str_contains($function, '::')) {\n                [$class] = explode('::', $function, 2);\n                if (class_exists($class) || interface_exists($class) || trait_exists($class)) {\n                    /** @var class-string<object> $class */\n                    $ref = new ReflectionClass($class);\n                    $fileName = $ref->getFileName();\n                }\n            } elseif (\\function_exists($function)) {\n                $ref = new ReflectionFunction($function);\n                $fileName = $ref->getFileName();\n            }\n        } catch (Throwable $e) {\n        }\n\n        if ($fileName === null || $fileName === false) {\n            return self::$calleeVendorCache[$function] = false;\n        }\n\n        $normalized = PathMatcher::normalizePath($fileName);\n\n        return self::$calleeVendorCache[$function] = PathMatcher::isVendorPath($normalized);\n    }\n\n    /**\n     * Inspects the call stack to see if the caller originated from vendor code.\n     */\n    public static function isCallerVendor(): bool\n    {\n        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10);\n\n        for ($i = 1; $i < \\count($trace); $i++) {\n            $frame = $trace[$i];\n            $class = $frame['class'] ?? '';\n            $function = $frame['function'];\n            $file = $frame['file'] ?? '';\n            if ($class !== '' && (str_starts_with($class, 'TypePHP\\\\Internal\\\\') || $class === 'TypePHP\\\\TypePHP')) {\n                continue;\n            }\n\n            if ($class === '' && \\in_array($function, ['call_user_func', 'call_user_func_array'], true)) {\n                continue;\n            }\n\n            if ($file === '') {\n                continue;\n            }\n\n            $normalizedFile = PathMatcher::normalizePath($file);\n\n            if (PathMatcher::isLibraryInternal($normalizedFile)) {\n                continue;\n            }\n\n            if (\n                str_contains($normalizedFile, '/vendor/phpunit/')\n                || str_contains($normalizedFile, '/vendor/pestphp/')\n            ) {\n                continue;\n            }\n\n            if (isset(self::$callerVendorCache[$normalizedFile])) {\n                return self::$callerVendorCache[$normalizedFile];\n            }\n\n            $isVendor = PathMatcher::isVendorPath($normalizedFile);\n\n            return self::$callerVendorCache[$normalizedFile] = $isVendor;\n        }\n\n        return false;\n    }\n}\n","/typephp/src/Internal/Resolver/HierarchyResolver.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Resolver;\n\nuse ReflectionClass;\nuse ReflectionMethod;\n\n/**\n * @internal Resolves class, interface, trait, and method inheritance hierarchies from child to root.\n */\nfinal class HierarchyResolver\n{\n    /**\n     * In-memory cache for resolved ReflectionMethod hierarchy arrays.\n     *\n     * @var array<string, array<int, ReflectionMethod>>\n     */\n    private static array $methodHierarchyCache = [];\n\n    /**\n     * In-memory cache for resolved ReflectionClass hierarchy arrays.\n     *\n     * @var array<string, array<int, ReflectionClass<object>>>\n     */\n    private static array $classHierarchyCache = [];\n\n    /**\n     * In-memory cache for class trait aliases.\n     *\n     * @var array<string, array<string, string>>\n     */\n    private static array $traitAliasCache = [];\n\n    /**\n     * Boolean fast-path cache: true if class has trait aliases, false if not.\n     * Avoids array allocation and comparison for the common \"no traits\" case.\n     *\n     * @var array<string, bool>\n     */\n    private static array $hasTraitAliasesCache = [];\n\n    /**\n     * Cache for 4-way class/interface/trait/enum existence checks.\n     * Avoids repeated existence checks for the same class name.\n     *\n     * @var array<string, bool>\n     */\n    private static array $classExistsCache = [];\n\n    /**\n     * Resets the hierarchy cache. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$methodHierarchyCache = [];\n        self::$classHierarchyCache = [];\n        self::$traitAliasCache = [];\n        self::$hasTraitAliasesCache = [];\n        self::$classExistsCache = [];\n    }\n\n    /**\n     * Checks whether a class, interface, trait, or enum exists.\n     * Caches the result to avoid repeated 4-way existence checks.\n     */\n    private static function typeExists(string $className): bool\n    {\n        if (isset(self::$classExistsCache[$className])) {\n            return self::$classExistsCache[$className];\n        }\n\n        $exists = class_exists($className, false)\n            || class_exists($className)\n            || interface_exists($className)\n            || trait_exists($className)\n            || enum_exists($className);\n\n        return self::$classExistsCache[$className] = $exists;\n    }\n\n    /**\n     * Returns cached trait aliases for a given class.\n     *\n     * Optimized with boolean fast-path cache to avoid reflection\n     * for classes known to not use traits.\n     *\n     * @return array<string, string>\n     */\n    public static function getTraitAliases(string $className): array\n    {\n        if (isset(self::$hasTraitAliasesCache[$className])) {\n            if (! self::$hasTraitAliasesCache[$className]) {\n                return [];\n            }\n\n            return self::$traitAliasCache[$className];\n        }\n\n        if (isset(self::$traitAliasCache[$className])) {\n            return self::$traitAliasCache[$className];\n        }\n\n        if (! self::typeExists($className)) {\n            self::$hasTraitAliasesCache[$className] = false;\n\n            return self::$traitAliasCache[$className] = [];\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $ref = new ReflectionClass($className);\n            $aliases = $ref->getTraitAliases();\n\n            self::$hasTraitAliasesCache[$className] = ($aliases !== []);\n\n            return self::$traitAliasCache[$className] = $aliases;\n        } catch (\\Throwable $e) {\n            self::$hasTraitAliasesCache[$className] = false;\n\n            return self::$traitAliasCache[$className] = [];\n        }\n    }\n\n    /**\n     * Builds an array of ReflectionMethods representing the inheritance hierarchy from child to root.\n     *\n     * @return array<int, ReflectionMethod>\n     */\n    public static function getMethodHierarchy(ReflectionMethod $ref): array\n    {\n        $cacheKey = $ref->class . '::' . $ref->getName();\n        if (isset(self::$methodHierarchyCache[$cacheKey])) {\n            return self::$methodHierarchyCache[$cacheKey];\n        }\n\n        $hierarchy = [$ref];\n        $methodName = $ref->getName();\n        $targetClassName = $ref->class;\n\n        $targetClass = new ReflectionClass($targetClassName);\n\n        $traitAliases = self::getTraitAliases($targetClassName);\n        if (isset($traitAliases[$methodName])) {\n            [$traitName, $originalMethodName] = explode('::', $traitAliases[$methodName], 2);\n            if (trait_exists($traitName)) {\n                $traitRef = new ReflectionClass($traitName);\n                if ($traitRef->hasMethod($originalMethodName)) {\n                    $hierarchy[] = $traitRef->getMethod($originalMethodName);\n                }\n            }\n        }\n\n        $parent = $targetClass->getParentClass();\n        while ($parent !== false) {\n            if ($parent->hasMethod($methodName)) {\n                $hierarchy[] = $parent->getMethod($methodName);\n            }\n            $parent = $parent->getParentClass();\n        }\n\n        foreach ($targetClass->getInterfaces() as $interface) {\n            if ($interface->hasMethod($methodName)) {\n                $hierarchy[] = $interface->getMethod($methodName);\n            }\n        }\n\n        foreach ($targetClass->getTraits() as $trait) {\n            if ($trait->hasMethod($methodName)) {\n                $hierarchy[] = $trait->getMethod($methodName);\n            }\n        }\n\n        return self::$methodHierarchyCache[$cacheKey] = $hierarchy;\n    }\n\n    /**\n     * Builds an array of ReflectionClasses representing the complete inheritance hierarchy from child to root.\n     * Recursively traverses parent classes, implemented interfaces, and used traits across all levels.\n     *\n     * @param ReflectionClass<object> $ref\n     *\n     * @return array<int, ReflectionClass<object>>\n     */\n    public static function getClassHierarchy(ReflectionClass $ref): array\n    {\n        $cacheKey = $ref->getName();\n        if (isset(self::$classHierarchyCache[$cacheKey])) {\n            return self::$classHierarchyCache[$cacheKey];\n        }\n\n        $hierarchy = [];\n        $visited = [];\n\n        $collect = function (ReflectionClass $class) use (&$collect, &$hierarchy, &$visited): void {\n            $name = $class->getName();\n            if (isset($visited[$name])) {\n                return;\n            }\n            $visited[$name] = true;\n            $hierarchy[] = $class;\n\n            $parent = $class->getParentClass();\n            if ($parent !== false) {\n                $collect($parent);\n            }\n\n            foreach ($class->getInterfaces() as $interface) {\n                $collect($interface);\n            }\n\n            foreach ($class->getTraits() as $trait) {\n                $collect($trait);\n            }\n        };\n\n        $collect($ref);\n\n        return self::$classHierarchyCache[$cacheKey] = $hierarchy;\n    }\n}\n","/typephp/src/Internal/Resolver/SpecialTypeResolver.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Resolver;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\n\n/**\n * Resolves special type identifiers (self, static, parent, FQCNs) against Reflection or file contexts.\n *\n * @internal\n */\nfinal class SpecialTypeResolver\n{\n    /**\n     * Fast lookup set for built-in PHP and PHPDoc type keywords.\n     */\n    private const BUILTIN_TYPE_KEYWORDS = [\n        'int' => true,\n        'integer' => true,\n        'string' => true,\n        'float' => true,\n        'double' => true,\n        'bool' => true,\n        'boolean' => true,\n        'array' => true,\n        'list' => true,\n        'object' => true,\n        'callable' => true,\n        'iterable' => true,\n        'resource' => true,\n        'null' => true,\n        'true' => true,\n        'false' => true,\n        'mixed' => true,\n        'scalar' => true,\n        'void' => true,\n        'self' => true,\n        'static' => true,\n        'parent' => true,\n        '$this' => true,\n        'positive-int' => true,\n        'negative-int' => true,\n        'non-positive-int' => true,\n        'non-negative-int' => true,\n        'non-zero-int' => true,\n        'unsigned-int' => true,\n        'positive-float' => true,\n        'negative-float' => true,\n        'non-positive-float' => true,\n        'non-negative-float' => true,\n        'non-zero-float' => true,\n        'class-string' => true,\n        'interface-string' => true,\n        'trait-string' => true,\n        'enum-string' => true,\n        'callable-string' => true,\n        'numeric-string' => true,\n        'non-empty-string' => true,\n        'lowercase-string' => true,\n        'non-empty-lowercase-string' => true,\n        'uppercase-string' => true,\n        'non-empty-uppercase-string' => true,\n        'array-key' => true,\n        'literal-string' => true,\n        'truthy-string' => true,\n        'non-empty-array' => true,\n        'non-empty-list' => true,\n        'number' => true,\n        'numeric' => true,\n        'truthy' => true,\n        'falsy' => true,\n        'falsey' => true,\n        'min' => true,\n        'max' => true,\n        '*' => true,\n        'never' => true,\n        'never-return' => true,\n        'never-returns' => true,\n        'no-return' => true,\n        'open-resource' => true,\n        'closed-resource' => true,\n    ];\n\n    /**\n     * In-memory cache for Reflection instances per context string.\n     *\n     * @var array<string, \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod>\n     */\n    private static array $reflectionContextCache = [];\n\n    /**\n     * In-memory 2D cache for resolved FQCNs: [$contextKey][$name] => FQCN.\n     *\n     * @var array<string, array<string, string>>\n     */\n    private static array $fqcnCache = [];\n\n    /**\n     * In-memory 2D cache for file FQCN resolutions: [$file][$name] => FQCN.\n     *\n     * @var array<string, array<string, string>>\n     */\n    private static array $fileFqcnCache = [];\n\n    /**\n     * In-memory 2D cache for class constant values: [$fqcn][$constName] => mixed.\n     *\n     * @var array<string, array<string, mixed>>\n     */\n    private static array $classConstantCache = [];\n\n    /**\n     * In-memory cache of file import maps keyed by filename.\n     *\n     * @var array<string, array<string, string>>\n     */\n    private static array $fileUseImports = [];\n\n    /**\n     * In-memory cache of file namespaces keyed by filename.\n     *\n     * @var array<string, string>\n     */\n    private static array $fileNamespaces = [];\n\n    /**\n     * In-memory cache of class trait use statement docblocks keyed by class FQCN.\n     *\n     * @var array<string, array<int, string>>\n     */\n    private static array $classTraitUseDocs = [];\n\n    /**\n     * In-memory cache of anonymous class trait use statement docblocks keyed by file and start line.\n     *\n     * @var array<string, array<int, array<int, string>>>\n     */\n    private static array $anonymousTraitUseDocs = [];\n\n    /**\n     * Resets reflection context and dynamic caches. Preserves static file imports.\n     */\n    public static function reset(): void\n    {\n        self::$reflectionContextCache = [];\n        self::$fqcnCache = [];\n        self::$fileFqcnCache = [];\n        self::$classConstantCache = [];\n        self::$classTraitUseDocs = [];\n        self::$anonymousTraitUseDocs = [];\n    }\n\n    /**\n     * Validates strict object identity ($value === $thisObj) when the return type node specifies $this.\n     */\n    public static function checkThisIdentity(TypeNode $returnTypeNode, mixed $value, ?object $thisObj, string $function): ?ErrorMessage\n    {\n        $isThisType = ($returnTypeNode instanceof ThisTypeNode)\n            || ($returnTypeNode instanceof IdentifierTypeNode && strtolower($returnTypeNode->name) === '$this');\n\n        if ($thisObj !== null && $isThisType && $value !== $thisObj) {\n            return ErrorFactory::createError($function . '(): Return value must be $this instance, ' . TypeFormatter::formatGivenValue($value) . ' returned');\n        }\n\n        return null;\n    }\n\n    /**\n     * Recursively resolves special type identifiers in a TypeNode AST using Reflection context.\n     *\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    public static function resolve(TypeNode $node, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context, ?object $thisObj = null): TypeNode\n    {\n        if ($node instanceof IdentifierTypeNode) {\n            $lower = strtolower($node->name);\n            if (isset(self::BUILTIN_TYPE_KEYWORDS[$lower]) && $lower !== 'self' && $lower !== 'parent' && $lower !== 'static' && $lower !== '$this') {\n                return $node;\n            }\n        }\n\n        $ref = self::getReflectionContext($context);\n        $declaringClass = $ref instanceof \\ReflectionMethod ? $ref->getDeclaringClass()->getName() : ($ref instanceof \\ReflectionClass ? $ref->getName() : null);\n\n        if ($node instanceof ThisTypeNode) {\n            return $node;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            return self::resolveIdentifier($node, $declaringClass, $ref, $context, $thisObj);\n        }\n\n        if ($node instanceof ConstTypeNode) {\n            return self::resolveConstType($node, $declaringClass, $ref);\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            $genericType = self::resolve($node->type, $context, $thisObj);\n            $innerTypes = array_map(fn ($t) => self::resolve($t, $context, $thisObj), $node->genericTypes);\n\n            return new GenericTypeNode(\n                $genericType instanceof IdentifierTypeNode ? $genericType : $node->type,\n                $innerTypes,\n                $node->variances\n            );\n        }\n\n        if ($node instanceof OffsetAccessTypeNode) {\n            return self::resolveOffsetAccess($node, $context, $thisObj);\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            return self::resolveArrayShape($node, $context, $thisObj);\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            return self::resolveObjectShape($node, $context, $thisObj);\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            return self::resolveCallable($node, $context, $thisObj);\n        }\n\n        if ($node instanceof ConditionalTypeNode) {\n            return new ConditionalTypeNode(\n                self::resolve($node->subjectType, $context, $thisObj),\n                self::resolve($node->targetType, $context, $thisObj),\n                self::resolve($node->if, $context, $thisObj),\n                self::resolve($node->else, $context, $thisObj),\n                $node->negated\n            );\n        }\n\n        if ($node instanceof ConditionalTypeForParameterNode) {\n            return new ConditionalTypeForParameterNode(\n                $node->parameterName,\n                self::resolve($node->targetType, $context, $thisObj),\n                self::resolve($node->if, $context, $thisObj),\n                self::resolve($node->else, $context, $thisObj),\n                $node->negated\n            );\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return new NullableTypeNode(self::resolve($node->type, $context, $thisObj));\n        }\n\n        if ($node instanceof ArrayTypeNode) {\n            return new ArrayTypeNode(self::resolve($node->type, $context, $thisObj));\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            return new UnionTypeNode(array_map(fn ($t) => self::resolve($t, $context, $thisObj), $node->types));\n        }\n\n        if ($node instanceof IntersectionTypeNode) {\n            return new IntersectionTypeNode(array_map(fn ($t) => self::resolve($t, $context, $thisObj), $node->types));\n        }\n\n        return $node;\n    }\n\n    /**\n     * Recursively resolves type identifiers in a TypeNode AST using file context (use imports and namespace).\n     */\n    public static function resolveForFile(TypeNode $node, string $file): TypeNode\n    {\n        $file = str_replace('\\\\', '/', $file);\n\n        if ($node instanceof ThisTypeNode) {\n            return clone $node;\n        }\n\n        if ($node instanceof IdentifierTypeNode) {\n            $lower = strtolower($node->name);\n            if (\\in_array($lower, ['self', 'static', 'parent', '$this'], strict: true)) {\n                return clone $node;\n            }\n\n            $fqcn = self::resolveFqcnForFile($node->name, $file);\n\n            return $fqcn !== $node->name ? new IdentifierTypeNode($fqcn) : clone $node;\n        }\n\n        if ($node instanceof ConstTypeNode) {\n            return self::resolveConstTypeForFile($node, $file);\n        }\n\n        if ($node instanceof GenericTypeNode) {\n            $genericType = self::resolveForFile($node->type, $file);\n            $innerTypes = array_map(fn ($t) => self::resolveForFile($t, $file), $node->genericTypes);\n\n            return new GenericTypeNode(\n                $genericType instanceof IdentifierTypeNode ? $genericType : $node->type,\n                $innerTypes,\n                $node->variances\n            );\n        }\n\n        if ($node instanceof OffsetAccessTypeNode) {\n            return self::resolveOffsetAccessForFile($node, $file);\n        }\n\n        if ($node instanceof ArrayShapeNode) {\n            return self::resolveArrayShapeForFile($node, $file);\n        }\n\n        if ($node instanceof ObjectShapeNode) {\n            return self::resolveObjectShapeForFile($node, $file);\n        }\n\n        if ($node instanceof CallableTypeNode) {\n            return self::resolveCallableForFile($node, $file);\n        }\n\n        if ($node instanceof ConditionalTypeNode) {\n            return new ConditionalTypeNode(\n                self::resolveForFile($node->subjectType, $file),\n                self::resolveForFile($node->targetType, $file),\n                self::resolveForFile($node->if, $file),\n                self::resolveForFile($node->else, $file),\n                $node->negated\n            );\n        }\n\n        if ($node instanceof ConditionalTypeForParameterNode) {\n            return new ConditionalTypeForParameterNode(\n                $node->parameterName,\n                self::resolveForFile($node->targetType, $file),\n                self::resolveForFile($node->if, $file),\n                self::resolveForFile($node->else, $file),\n                $node->negated\n            );\n        }\n\n        if ($node instanceof NullableTypeNode) {\n            return new NullableTypeNode(self::resolveForFile($node->type, $file));\n        }\n\n        if ($node instanceof ArrayTypeNode) {\n            return new ArrayTypeNode(self::resolveForFile($node->type, $file));\n        }\n\n        if ($node instanceof UnionTypeNode) {\n            return new UnionTypeNode(array_map(fn ($t) => self::resolveForFile($t, $file), $node->types));\n        }\n\n        if ($node instanceof IntersectionTypeNode) {\n            return new IntersectionTypeNode(array_map(fn ($t) => self::resolveForFile($t, $file), $node->types));\n        }\n\n        return clone $node;\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     *\n     * @return \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod\n     */\n    private static function getReflectionContext(\\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context): \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod\n    {\n        if (\\is_string($context)) {\n            if (isset(self::$reflectionContextCache[$context])) {\n                return self::$reflectionContextCache[$context];\n            }\n\n            if (str_contains($context, '::')) {\n                [$className, $methodName] = explode('::', $context, 2);\n\n                if (class_exists($className) || interface_exists($className) || trait_exists($className) || enum_exists($className)) {\n                    /** @var class-string<object> $className */\n                    try {\n                        return self::$reflectionContextCache[$context] = new \\ReflectionMethod($className, $methodName);\n                    } catch (\\ReflectionException $e) {\n                        return self::$reflectionContextCache[$context] = new \\ReflectionClass($className);\n                    }\n                }\n\n                /** @var class-string<object> $fallbackClass */\n                $fallbackClass = \\stdClass::class;\n\n                return self::$reflectionContextCache[$context] = new \\ReflectionClass($fallbackClass);\n            }\n\n            if (class_exists($context) || interface_exists($context) || trait_exists($context) || enum_exists($context)) {\n                /** @var class-string<object> $context */\n                return self::$reflectionContextCache[$context] = new \\ReflectionClass($context);\n            }\n\n            try {\n                return self::$reflectionContextCache[$context] = new \\ReflectionFunction($context);\n            } catch (\\ReflectionException $e) {\n                /** @var class-string<object> $fallbackClass */\n                $fallbackClass = \\stdClass::class;\n\n                return self::$reflectionContextCache[$context] = new \\ReflectionClass($fallbackClass);\n            }\n        }\n\n        return $context;\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod $ref\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    private static function resolveIdentifier(\n        IdentifierTypeNode $node,\n        ?string $declaringClass,\n        \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod $ref,\n        \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context,\n        ?object $thisObj = null\n    ): IdentifierTypeNode {\n        $lower = strtolower($node->name);\n\n        if ($lower === '$this') {\n            if ($thisObj !== null) {\n                return new IdentifierTypeNode(\\get_class($thisObj));\n            }\n\n            return $node;\n        }\n\n        if ($lower === 'static') {\n            if ($thisObj !== null) {\n                return new IdentifierTypeNode(\\get_class($thisObj));\n            }\n\n            if (\\is_string($context) && str_contains($context, '::')) {\n                $callingClass = explode('::', $context, 2)[0];\n                if (class_exists($callingClass) || interface_exists($callingClass) || trait_exists($callingClass) || enum_exists($callingClass)) {\n                    return new IdentifierTypeNode($callingClass);\n                }\n            }\n\n            return $node;\n        }\n\n        if ($lower === 'self' && $declaringClass !== null) {\n            return new IdentifierTypeNode($declaringClass);\n        }\n\n        if ($lower === 'parent' && $declaringClass !== null) {\n            $parentClass = get_parent_class($declaringClass);\n            if ($parentClass !== false) {\n                return new IdentifierTypeNode($parentClass);\n            }\n        }\n\n        $fqcn = self::resolveFqcn($node->name, $ref);\n\n        return $fqcn !== $node->name ? new IdentifierTypeNode($fqcn) : $node;\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod $ref\n     */\n    private static function resolveConstType(ConstTypeNode $node, ?string $declaringClass, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod $ref): ConstTypeNode\n    {\n        if ($node->constExpr instanceof ConstFetchNode && $node->constExpr->className !== '') {\n            $className = $node->constExpr->className;\n            $lowerClassName = strtolower($className);\n\n            if ($lowerClassName === 'self' && $declaringClass !== null) {\n                $resolvedClass = $declaringClass;\n            } elseif ($lowerClassName === 'parent' && $declaringClass !== null) {\n                $parentClass = get_parent_class($declaringClass);\n                $resolvedClass = $parentClass !== false ? $parentClass : $className;\n            } else {\n                $resolvedClass = self::resolveFqcn($className, $ref);\n            }\n\n            return new ConstTypeNode(new ConstFetchNode($resolvedClass, $node->constExpr->name));\n        }\n\n        return $node;\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    private static function resolveOffsetAccess(OffsetAccessTypeNode $node, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context, ?object $thisObj): TypeNode\n    {\n        $baseType = self::resolve($node->type, $context, $thisObj);\n        $offsetType = self::resolve($node->offset, $context, $thisObj);\n\n        $offsetKey = self::extractOffsetKey($offsetType);\n\n        if ($offsetKey !== null) {\n            if ($baseType instanceof ArrayShapeNode) {\n                foreach ($baseType->items as $item) {\n                    $itemKey = self::extractItemKey($item->keyName);\n                    if ((string) $itemKey === (string) $offsetKey) {\n                        return $item->valueType;\n                    }\n                }\n            }\n\n            if ($baseType instanceof ConstTypeNode && $baseType->constExpr instanceof ConstFetchNode) {\n                $resolvedNode = self::resolveConstantOffsetValue($baseType->constExpr->className, $baseType->constExpr->name, $offsetKey);\n                if ($resolvedNode !== null) {\n                    return $resolvedNode;\n                }\n            }\n        }\n\n        return new OffsetAccessTypeNode($baseType, $offsetType);\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    private static function resolveArrayShape(ArrayShapeNode $node, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context, ?object $thisObj): ArrayShapeNode\n    {\n        $ref = self::getReflectionContext($context);\n        $items = array_map(function ($item) use ($ref, $context, $thisObj) {\n            /** @var ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null $keyName */\n            $keyName = $item->keyName;\n\n            $className = null;\n            $constName = null;\n\n            if ($keyName instanceof ConstFetchNode && $keyName->className !== '') {\n                $className = $keyName->className;\n                $constName = $keyName->name;\n            } elseif ($keyName instanceof IdentifierTypeNode && str_contains($keyName->name, '::')) {\n                [$className, $constName] = explode('::', $keyName->name, 2);\n            } elseif ($keyName instanceof ConstExprStringNode && str_contains($keyName->value, '::')) {\n                [$className, $constName] = explode('::', $keyName->value, 2);\n            }\n\n            if ($className !== null && $constName !== null) {\n                $lowerClassName = strtolower($className);\n                $declaringClass = $ref instanceof \\ReflectionMethod ? $ref->getDeclaringClass()->getName() : null;\n\n                if ($lowerClassName === 'self' && $declaringClass !== null) {\n                    $resolvedClass = $declaringClass;\n                } elseif ($lowerClassName === 'parent' && $declaringClass !== null) {\n                    $parentClass = get_parent_class($declaringClass);\n                    $resolvedClass = $parentClass !== false ? $parentClass : $className;\n                } else {\n                    $resolvedClass = self::resolveFqcn($className, $ref);\n                }\n\n                $resolvedKeyNode = self::resolveConstantKeyValue($resolvedClass, $constName);\n                if ($resolvedKeyNode !== null) {\n                    $keyName = $resolvedKeyNode;\n                }\n            }\n\n            return new ArrayShapeItemNode(\n                $keyName,\n                $item->optional,\n                self::resolve($item->valueType, $context, $thisObj)\n            );\n        }, $node->items);\n\n        if ($node->sealed) {\n            return ArrayShapeNode::createSealed($items, $node->kind);\n        }\n\n        $unsealedType = null;\n        if ($node->unsealedType !== null) {\n            $unsealedKey = $node->unsealedType->keyType !== null ? self::resolve($node->unsealedType->keyType, $context, $thisObj) : null;\n            $unsealedValue = self::resolve($node->unsealedType->valueType, $context, $thisObj);\n            $unsealedType = new ArrayShapeUnsealedTypeNode($unsealedValue, $unsealedKey);\n        }\n\n        return ArrayShapeNode::createUnsealed($items, $unsealedType, $node->kind);\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    private static function resolveObjectShape(ObjectShapeNode $node, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context, ?object $thisObj): ObjectShapeNode\n    {\n        $items = array_map(function ($item) use ($context, $thisObj) {\n            return new ObjectShapeItemNode(\n                $item->keyName,\n                $item->optional,\n                self::resolve($item->valueType, $context, $thisObj)\n            );\n        }, $node->items);\n\n        return new ObjectShapeNode($items);\n    }\n\n    /**\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod|string $context\n     */\n    private static function resolveCallable(CallableTypeNode $node, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod|string $context, ?object $thisObj): CallableTypeNode\n    {\n        $resolvedParameters = array_map(function (CallableTypeParameterNode $param) use ($context, $thisObj) {\n            return new CallableTypeParameterNode(\n                self::resolve($param->type, $context, $thisObj),\n                $param->isReference,\n                $param->isVariadic,\n                $param->parameterName,\n                $param->isOptional\n            );\n        }, $node->parameters);\n\n        $resolvedReturnType = self::resolve($node->returnType, $context, $thisObj);\n\n        return new CallableTypeNode($node->identifier, $resolvedParameters, $resolvedReturnType, $node->templateTypes);\n    }\n\n    private static function resolveConstTypeForFile(ConstTypeNode $node, string $file): ConstTypeNode\n    {\n        if ($node->constExpr instanceof ConstFetchNode && $node->constExpr->className !== '') {\n            $className = $node->constExpr->className;\n            $lowerClassName = strtolower($className);\n\n            if ($lowerClassName === 'self' || $lowerClassName === 'parent') {\n                $resolvedClass = $className;\n            } else {\n                $resolvedClass = self::resolveFqcnForFile($className, $file);\n            }\n\n            return new ConstTypeNode(new ConstFetchNode($resolvedClass, $node->constExpr->name));\n        }\n\n        return clone $node;\n    }\n\n    private static function resolveOffsetAccessForFile(OffsetAccessTypeNode $node, string $file): TypeNode\n    {\n        $baseType = self::resolveForFile($node->type, $file);\n        $offsetType = self::resolveForFile($node->offset, $file);\n\n        $offsetKey = self::extractOffsetKey($offsetType);\n\n        if ($offsetKey !== null) {\n            if ($baseType instanceof ArrayShapeNode) {\n                foreach ($baseType->items as $item) {\n                    $itemKey = self::extractItemKey($item->keyName);\n                    if ((string) $itemKey === (string) $offsetKey) {\n                        return $item->valueType;\n                    }\n                }\n            }\n\n            if ($baseType instanceof ConstTypeNode && $baseType->constExpr instanceof ConstFetchNode) {\n                $resolvedNode = self::resolveConstantOffsetValue($baseType->constExpr->className, $baseType->constExpr->name, $offsetKey);\n                if ($resolvedNode !== null) {\n                    return $resolvedNode;\n                }\n            }\n        }\n\n        return new OffsetAccessTypeNode($baseType, $offsetType);\n    }\n\n    private static function resolveArrayShapeForFile(ArrayShapeNode $node, string $file): ArrayShapeNode\n    {\n        $items = array_map(function ($item) use ($file) {\n            /** @var ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null $keyName */\n            $keyName = $item->keyName;\n\n            $className = null;\n            $constName = null;\n\n            if ($keyName instanceof ConstFetchNode && $keyName->className !== '') {\n                $className = $keyName->className;\n                $constName = $keyName->name;\n            } elseif ($keyName instanceof IdentifierTypeNode && str_contains($keyName->name, '::')) {\n                [$className, $constName] = explode('::', $keyName->name, 2);\n            } elseif ($keyName instanceof ConstExprStringNode && str_contains($keyName->value, '::')) {\n                [$className, $constName] = explode('::', $keyName->value, 2);\n            }\n\n            if ($className !== null && $constName !== null) {\n                $lowerClassName = strtolower($className);\n\n                if ($lowerClassName !== 'self' && $lowerClassName !== 'parent') {\n                    $resolvedClass = self::resolveFqcnForFile($className, $file);\n                    $resolvedKeyNode = self::resolveConstantKeyValue($resolvedClass, $constName);\n                    if ($resolvedKeyNode !== null) {\n                        $keyName = $resolvedKeyNode;\n                    }\n                }\n            }\n\n            return new ArrayShapeItemNode(\n                $keyName,\n                $item->optional,\n                self::resolveForFile($item->valueType, $file)\n            );\n        }, $node->items);\n\n        if ($node->sealed) {\n            return ArrayShapeNode::createSealed($items, $node->kind);\n        }\n\n        $unsealedType = null;\n        if ($node->unsealedType !== null) {\n            $unsealedKey = $node->unsealedType->keyType !== null ? self::resolveForFile($node->unsealedType->keyType, $file) : null;\n            $unsealedValue = self::resolveForFile($node->unsealedType->valueType, $file);\n            $unsealedType = new ArrayShapeUnsealedTypeNode($unsealedValue, $unsealedKey);\n        }\n\n        return ArrayShapeNode::createUnsealed($items, $unsealedType, $node->kind);\n    }\n\n    private static function resolveObjectShapeForFile(ObjectShapeNode $node, string $file): ObjectShapeNode\n    {\n        $items = array_map(function ($item) use ($file) {\n            return new ObjectShapeItemNode(\n                $item->keyName,\n                $item->optional,\n                self::resolveForFile($item->valueType, $file)\n            );\n        }, $node->items);\n\n        return new ObjectShapeNode($items);\n    }\n\n    private static function resolveCallableForFile(CallableTypeNode $node, string $file): CallableTypeNode\n    {\n        $resolvedParameters = array_map(function (CallableTypeParameterNode $param) use ($file) {\n            return new CallableTypeParameterNode(\n                self::resolveForFile($param->type, $file),\n                $param->isReference,\n                $param->isVariadic,\n                $param->parameterName,\n                $param->isOptional\n            );\n        }, $node->parameters);\n\n        $resolvedReturnType = self::resolveForFile($node->returnType, $file);\n\n        return new CallableTypeNode($node->identifier, $resolvedParameters, $resolvedReturnType, $node->templateTypes);\n    }\n\n    private static function extractOffsetKey(TypeNode $offsetType): string|int|null\n    {\n        if ($offsetType instanceof ConstTypeNode) {\n            $expr = $offsetType->constExpr;\n            if ($expr instanceof ConstExprStringNode) {\n                return $expr->value;\n            }\n            if ($expr instanceof ConstExprIntegerNode) {\n                return (int) $expr->value;\n            }\n        }\n        if ($offsetType instanceof IdentifierTypeNode) {\n            return $offsetType->name;\n        }\n\n        return null;\n    }\n\n    private static function extractItemKey(mixed $keyName): string|int|null\n    {\n        if ($keyName instanceof ConstExprStringNode) {\n            return $keyName->value;\n        }\n        if ($keyName instanceof IdentifierTypeNode) {\n            return $keyName->name;\n        }\n        if ($keyName instanceof ConstExprIntegerNode) {\n            return (int) $keyName->value;\n        }\n\n        return null;\n    }\n\n    /**\n     * Resolves and caches class constant values in memory.\n     */\n    private static function getClassConstant(string $fqcn, string $constName): mixed\n    {\n        if (! isset(self::$classConstantCache[$fqcn][$constName]) && ! \\array_key_exists($constName, self::$classConstantCache[$fqcn] ?? [])) {\n            $val = null;\n            if ($fqcn !== '' && self::symbolExists($fqcn)) {\n                try {\n                    /** @var class-string<object> $fqcn */\n                    $refClass = new \\ReflectionClass($fqcn);\n                    if ($refClass->hasConstant($constName)) {\n                        $val = $refClass->getConstant($constName);\n                    }\n                } catch (\\ReflectionException $e) {\n                }\n            }\n            self::$classConstantCache[$fqcn][$constName] = $val;\n        }\n\n        return self::$classConstantCache[$fqcn][$constName];\n    }\n\n    private static function resolveConstantOffsetValue(string $fqcn, string $constName, string|int $offsetKey): ?TypeNode\n    {\n        $constValue = self::getClassConstant($fqcn, $constName);\n        if (\\is_array($constValue) && \\array_key_exists($offsetKey, $constValue)) {\n            $val = $constValue[$offsetKey];\n            if (\\is_string($val)) {\n                return new ConstTypeNode(new ConstExprStringNode($val, ConstExprStringNode::SINGLE_QUOTED));\n            }\n            if (\\is_int($val)) {\n                return new ConstTypeNode(new ConstExprIntegerNode((string) $val));\n            }\n        }\n\n        return null;\n    }\n\n    private static function resolveConstantKeyValue(string $fqcn, string $constName): ConstExprStringNode|ConstExprIntegerNode|null\n    {\n        $val = self::getClassConstant($fqcn, $constName);\n        if (\\is_string($val)) {\n            return new ConstExprStringNode($val, ConstExprStringNode::SINGLE_QUOTED);\n        }\n        if (\\is_int($val)) {\n            return new ConstExprIntegerNode((string) $val);\n        }\n\n        return null;\n    }\n\n    /**\n     * Seeds file metadata directly from StreamWrapper.\n     *\n     * @param array<string, string> $imports\n     * @param array<string, array<int, string>> $classTraitUseDocs\n     * @param array<int, array<int, string>> $anonymousTraitUseDocs\n     */\n    public static function seedFileMetadata(\n        string $fileName,\n        string $namespace,\n        array $imports,\n        array $classTraitUseDocs = [],\n        array $anonymousTraitUseDocs = []\n    ): void {\n        if ($fileName !== '') {\n            $fileName = str_replace('\\\\', '/', $fileName);\n            self::$fileNamespaces[$fileName] = $namespace;\n            self::$fileUseImports[$fileName] = $imports;\n            foreach ($classTraitUseDocs as $className => $docs) {\n                self::$classTraitUseDocs[$className] = $docs;\n            }\n            if ($anonymousTraitUseDocs !== []) {\n                self::$anonymousTraitUseDocs[$fileName] = $anonymousTraitUseDocs;\n            }\n        }\n    }\n\n    /**\n     * Returns all inline trait use statement docblock strings declared inside a class.\n     *\n     * @return array<int, string>\n     */\n    public static function getClassTraitUseDocs(string $className): array\n    {\n        if (isset(self::$classTraitUseDocs[$className])) {\n            return self::$classTraitUseDocs[$className];\n        }\n\n        if (! class_exists($className, false) && ! class_exists($className) && ! trait_exists($className)) {\n            return self::$classTraitUseDocs[$className] = [];\n        }\n\n        try {\n            /** @var class-string<object> $className */\n            $ref = new \\ReflectionClass($className);\n            $fileName = $ref->getFileName();\n            if ($fileName !== false) {\n                $normalizedFile = str_replace('\\\\', '/', $fileName);\n\n                if ($ref->isAnonymous()) {\n                    $startLine = $ref->getStartLine();\n                    $endLine = $ref->getEndLine();\n\n                    if ($startLine === false || $endLine === false) {\n                        return self::$classTraitUseDocs[$className] = [];\n                    }\n\n                    if (! isset(self::$anonymousTraitUseDocs[$normalizedFile]) && file_exists($fileName)) {\n                        $source = file_get_contents($fileName);\n                        if ($source !== false) {\n                            self::parseFileMetadata($fileName, $source);\n                        }\n                    }\n\n                    if (isset(self::$anonymousTraitUseDocs[$normalizedFile][$startLine])) {\n                        return self::$classTraitUseDocs[$className] = self::$anonymousTraitUseDocs[$normalizedFile][$startLine];\n                    }\n\n                    if (isset(self::$anonymousTraitUseDocs[$normalizedFile])) {\n                        foreach (self::$anonymousTraitUseDocs[$normalizedFile] as $line => $docs) {\n                            if ($line >= $startLine && $line <= $endLine) {\n                                return self::$classTraitUseDocs[$className] = $docs;\n                            }\n                        }\n\n                        $bestMatch = null;\n                        $minDiff = PHP_INT_MAX;\n                        foreach (self::$anonymousTraitUseDocs[$normalizedFile] as $line => $docs) {\n                            $diff = abs($line - $startLine);\n                            if ($diff <= 5 && $diff < $minDiff) {\n                                $minDiff = $diff;\n                                $bestMatch = $docs;\n                            }\n                        }\n\n                        if ($bestMatch !== null) {\n                            return self::$classTraitUseDocs[$className] = $bestMatch;\n                        }\n                    }\n\n                    return self::$classTraitUseDocs[$className] = [];\n                }\n\n                if (file_exists($fileName)) {\n                    $source = file_get_contents($fileName);\n                    if ($source !== false) {\n                        self::parseFileMetadata($fileName, $source);\n                    }\n                }\n            }\n        } catch (\\Throwable $e) {\n            // Silently ignore reflection errors\n        }\n\n        return self::$classTraitUseDocs[$className] ?? [];\n    }\n\n    /**\n     * Returns use imports for the declaring file of a Reflection object.\n     *\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod $ref\n     *\n     * @return array<string, string>\n     */\n    public static function getUseImports(\\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod $ref): array\n    {\n        $fileName = $ref->getFileName();\n        if ($fileName === false || ! file_exists($fileName)) {\n            return [];\n        }\n\n        return self::getUseImportsFromFile($fileName);\n    }\n\n    /**\n     * Extracts and caches use imports directly from a file path.\n     *\n     * @return array<string, string>\n     */\n    public static function getUseImportsFromFile(string $fileName): array\n    {\n        if ($fileName === '') {\n            return [];\n        }\n\n        $fileName = str_replace('\\\\', '/', $fileName);\n\n        if (isset(self::$fileUseImports[$fileName])) {\n            return self::$fileUseImports[$fileName];\n        }\n\n        if (! file_exists($fileName)) {\n            return [];\n        }\n\n        $source = file_get_contents($fileName);\n        if ($source === false) {\n            return self::$fileUseImports[$fileName] = [];\n        }\n\n        self::parseFileMetadata($fileName, $source);\n\n        return self::$fileUseImports[$fileName] ?? [];\n    }\n\n    /**\n     * Extracts and caches the namespace directly from a file path.\n     */\n    public static function getNamespaceFromFile(string $fileName): string\n    {\n        if ($fileName === '') {\n            return '';\n        }\n\n        $fileName = str_replace('\\\\', '/', $fileName);\n\n        if (isset(self::$fileNamespaces[$fileName])) {\n            return self::$fileNamespaces[$fileName];\n        }\n\n        if (! file_exists($fileName)) {\n            return '';\n        }\n\n        $source = file_get_contents($fileName);\n        if ($source === false) {\n            return self::$fileNamespaces[$fileName] = '';\n        }\n\n        self::parseFileMetadata($fileName, $source);\n\n        return self::$fileNamespaces[$fileName] ?? '';\n    }\n\n    /**\n     * Resolves a short class name to its fully qualified class name (FQCN) using Reflection context.\n     * Memoizes resolved FQCNs in memory via zero-allocation 2D table to avoid autoloader search storms.\n     *\n     * @param \\ReflectionClass<object>|\\ReflectionFunction|\\ReflectionMethod $ref\n     */\n    public static function resolveFqcn(string $name, \\ReflectionClass|\\ReflectionFunction|\\ReflectionMethod $ref): string\n    {\n        if (self::isBuiltInTypeKeyword($name)) {\n            return $name;\n        }\n\n        if (str_starts_with($name, '\\\\')) {\n            return ltrim($name, '\\\\');\n        }\n\n        if (! ClassNameValidator::isValid($name)) {\n            return $name;\n        }\n\n        $contextKey = match (true) {\n            $ref instanceof \\ReflectionClass => 'C:' . $ref->getName(),\n            $ref instanceof \\ReflectionMethod => 'M:' . ($ref->getFileName() !== false ? $ref->getFileName() : $ref->getDeclaringClass()->getName()) . '::' . $ref->getName(),\n            $ref instanceof \\ReflectionFunction => 'F:' . $ref->getName(),\n        };\n\n        if (isset(self::$fqcnCache[$contextKey][$name])) {\n            return self::$fqcnCache[$contextKey][$name];\n        }\n\n        $imports = self::getUseImports($ref);\n        $fileName = $ref->getFileName();\n        $fileNamespace = ($fileName !== false && $fileName !== '') ? self::getNamespaceFromFile($fileName) : '';\n\n        $namespace = ($fileNamespace !== '')\n            ? $fileNamespace\n            : match (true) {\n                $ref instanceof \\ReflectionClass => $ref->getNamespaceName(),\n                $ref instanceof \\ReflectionMethod => $ref->getDeclaringClass()->getNamespaceName(),\n                $ref instanceof \\ReflectionFunction => $ref->getNamespaceName(),\n            };\n\n        $resolved = self::resolveNameFromImportsAndNamespace($name, $imports, $namespace);\n\n        return self::$fqcnCache[$contextKey][$name] = $resolved;\n    }\n\n    /**\n     * Resolves a short class name to its FQCN purely based on file context with 2D caching.\n     */\n    public static function resolveFqcnForFile(string $name, string $file): string\n    {\n        $file = str_replace('\\\\', '/', $file);\n\n        if (self::isBuiltInTypeKeyword($name)) {\n            return $name;\n        }\n\n        if (str_starts_with($name, '\\\\')) {\n            return ltrim($name, '\\\\');\n        }\n\n        if (! ClassNameValidator::isValid($name)) {\n            return $name;\n        }\n\n        if (isset(self::$fileFqcnCache[$file][$name])) {\n            return self::$fileFqcnCache[$file][$name];\n        }\n\n        $imports = self::getUseImportsFromFile($file);\n        $namespace = self::getNamespaceFromFile($file);\n\n        return self::$fileFqcnCache[$file][$name] = self::resolveNameFromImportsAndNamespace($name, $imports, $namespace);\n    }\n\n    /**\n     * Common name resolution algorithm adhering to PHP standard name resolution rules.\n     *\n     * @param array<string, string> $imports\n     */\n    private static function resolveNameFromImportsAndNamespace(string $name, array $imports, string $namespace): string\n    {\n        if (isset($imports[$name])) {\n            return $imports[$name];\n        }\n\n        if (! str_contains($name, '\\\\')) {\n            if ($namespace !== '') {\n                $namespacedClass = $namespace . '\\\\' . $name;\n                if (self::symbolExists($namespacedClass)) {\n                    return $namespacedClass;\n                }\n            }\n\n            if (self::symbolExists($name)) {\n                return $name;\n            }\n\n            return $name;\n        }\n\n        if (self::symbolExists($name)) {\n            return $name;\n        }\n\n        [$firstPart, $subPart] = explode('\\\\', $name, 2);\n        if (isset($imports[$firstPart])) {\n            $candidate = $imports[$firstPart] . '\\\\' . $subPart;\n            if (self::symbolExists($candidate)) {\n                return $candidate;\n            }\n        }\n\n        if ($namespace !== '') {\n            $namespacedClass = $namespace . '\\\\' . $name;\n            if (self::symbolExists($namespacedClass)) {\n                return $namespacedClass;\n            }\n        }\n\n        return $name;\n    }\n\n    /**\n     * Fast-checks in-memory symbol tables before invoking autoloader.\n     */\n    private static function symbolExists(string $symbol): bool\n    {\n        return class_exists($symbol, false)\n            || interface_exists($symbol, false)\n            || enum_exists($symbol, false)\n            || trait_exists($symbol, false)\n            || class_exists($symbol)\n            || interface_exists($symbol)\n            || enum_exists($symbol)\n            || trait_exists($symbol);\n    }\n\n    /**\n     * Checks if a type name is a built-in PHP or PHPDoc type keyword.\n     */\n    public static function isBuiltInTypeKeyword(string $name): bool\n    {\n        return isset(self::BUILTIN_TYPE_KEYWORDS[strtolower($name)]);\n    }\n\n    /**\n     * Fast C-level token scanner using PhpToken (PHP 8.0+) to extract namespace,\n     * use imports, and trait docblocks in microseconds without PhpParser AST overhead.\n     */\n    public static function parseFileMetadata(string $fileName, string $source): void\n    {\n        $normalizedFile = str_replace('\\\\', '/', $fileName);\n        self::$fileNamespaces[$normalizedFile] = '';\n        self::$fileUseImports[$normalizedFile] = [];\n        self::$anonymousTraitUseDocs[$normalizedFile] = [];\n\n        try {\n            $tokens = \\PhpToken::tokenize($source);\n            $count = \\count($tokens);\n            $namespace = '';\n            $imports = [];\n\n            /** @var list<array{type: 'named'|'anon', name?: string, line?: int, depth: int}> $classStack */\n            $classStack = [];\n            /** @var array{type: 'named'|'anon', name?: string, line?: int}|null $pendingClass */\n            $pendingClass = null;\n            $braceDepth = 0;\n\n            for ($i = 0; $i < $count; $i++) {\n                $token = $tokens[$i];\n\n                if ($token->id === T_NAMESPACE) {\n                    $nsParts = [];\n                    for ($j = $i + 1; $j < $count; $j++) {\n                        if ($tokens[$j]->text === ';' || $tokens[$j]->text === '{') {\n                            $i = $j;\n\n                            break;\n                        }\n                        if ($tokens[$j]->id === T_NAME_QUALIFIED || $tokens[$j]->id === T_STRING || $tokens[$j]->id === T_NS_SEPARATOR) {\n                            $nsParts[] = $tokens[$j]->text;\n                        }\n                    }\n                    $namespace = trim(implode('', $nsParts));\n                    self::$fileNamespaces[$normalizedFile] = $namespace;\n\n                    continue;\n                }\n\n                $isClassLike = $token->id === T_CLASS || $token->id === T_INTERFACE || $token->id === T_TRAIT || (\\defined('T_ENUM') && $token->id === T_ENUM);\n\n                if ($isClassLike) {\n                    $isClassConst = false;\n                    for ($prev = $i - 1; $prev >= 0; $prev--) {\n                        if ($tokens[$prev]->id === T_WHITESPACE || $tokens[$prev]->id === T_COMMENT) {\n                            continue;\n                        }\n                        if ($tokens[$prev]->id === T_DOUBLE_COLON) {\n                            $isClassConst = true;\n                        }\n\n                        break;\n                    }\n\n                    if ($isClassConst) {\n                        continue;\n                    }\n\n                    $nameToken = null;\n                    for ($j = $i + 1; $j < $count; $j++) {\n                        if ($tokens[$j]->id === T_WHITESPACE || $tokens[$j]->id === T_COMMENT || $tokens[$j]->id === T_DOC_COMMENT) {\n                            continue;\n                        }\n                        if ($tokens[$j]->id === T_STRING) {\n                            $nameToken = $tokens[$j];\n                        }\n\n                        break;\n                    }\n\n                    if ($nameToken !== null) {\n                        $className = $namespace !== '' ? $namespace . '\\\\' . $nameToken->text : $nameToken->text;\n                        self::$classTraitUseDocs[$className] = [];\n                        $pendingClass = ['type' => 'named', 'name' => $className];\n                    } elseif ($token->id === T_CLASS) {\n                        $pendingClass = ['type' => 'anon', 'line' => $token->line];\n                    }\n\n                    continue;\n                }\n\n                if ($token->text === '{' || $token->id === T_CURLY_OPEN || $token->id === T_DOLLAR_OPEN_CURLY_BRACES) {\n                    $braceDepth++;\n                    if ($pendingClass !== null) {\n                        $classStack[] = [\n                            'type' => $pendingClass['type'],\n                            'name' => $pendingClass['name'] ?? null,\n                            'line' => $pendingClass['line'] ?? null,\n                            'depth' => $braceDepth,\n                        ];\n                        $pendingClass = null;\n                    }\n\n                    continue;\n                }\n\n                if ($token->text === '}') {\n                    if ($classStack !== []) {\n                        $top = end($classStack);\n                        if ($braceDepth === $top['depth']) {\n                            array_pop($classStack);\n                        }\n                    }\n                    $braceDepth--;\n\n                    continue;\n                }\n\n                if ($token->id === T_USE && $classStack !== []) {\n                    $isClosureUse = false;\n                    for ($j = $i + 1; $j < $count; $j++) {\n                        if ($tokens[$j]->id === T_WHITESPACE || $tokens[$j]->id === T_COMMENT) {\n                            continue;\n                        }\n                        if ($tokens[$j]->text === '(') {\n                            $isClosureUse = true;\n                        }\n\n                        break;\n                    }\n\n                    if (! $isClosureUse) {\n                        for ($k = $i - 1; $k >= 0; $k--) {\n                            if ($tokens[$k]->id === T_DOC_COMMENT) {\n                                $top = end($classStack);\n                                if ($top['type'] === 'named' && isset($top['name'])) {\n                                    self::$classTraitUseDocs[$top['name']][] = $tokens[$k]->text;\n                                } elseif ($top['type'] === 'anon' && isset($top['line'])) {\n                                    self::$anonymousTraitUseDocs[$normalizedFile][$top['line']][] = $tokens[$k]->text;\n                                }\n\n                                break;\n                            }\n                            if ($tokens[$k]->id !== T_WHITESPACE) {\n                                break;\n                            }\n                        }\n                    }\n\n                    continue;\n                }\n\n                if ($token->id === T_USE && $classStack === []) {\n                    $useStatement = '';\n                    for ($j = $i + 1; $j < $count; $j++) {\n                        if ($tokens[$j]->text === ';') {\n                            $i = $j;\n\n                            break;\n                        }\n                        if ($tokens[$j]->text === '{') {\n                            $prefix = trim($useStatement);\n                            $groupContent = '';\n                            for ($g = $j + 1; $g < $count; $g++) {\n                                if ($tokens[$g]->text === '}') {\n                                    $i = $g;\n\n                                    break;\n                                }\n                                $groupContent .= $tokens[$g]->text;\n                            }\n                            foreach (explode(',', $groupContent) as $part) {\n                                $part = trim($part);\n                                if ($part === '') {\n                                    continue;\n                                }\n                                if (preg_match('/^([a-zA-Z0-9_\\\\\\\\]+)(?:\\s+as\\s+([a-zA-Z0-9_]+))?$/i', $part, $m) === 1) {\n                                    $fqcn = rtrim($prefix, '\\\\') . '\\\\' . trim($m[1]);\n                                    $alias = $m[2] ?? basename(str_replace('\\\\', '/', $fqcn));\n                                    $imports[$alias] = ltrim($fqcn, '\\\\');\n                                }\n                            }\n\n                            break;\n                        }\n                        $useStatement .= $tokens[$j]->text;\n                    }\n\n                    if (str_contains($useStatement, ',')) {\n                        foreach (explode(',', $useStatement) as $part) {\n                            $part = trim($part);\n                            if ($part === '') {\n                                continue;\n                            }\n                            if (preg_match('/^(?:function\\s+|const\\s+)?([a-zA-Z0-9_\\\\\\\\]+)(?:\\s+as\\s+([a-zA-Z0-9_]+))?$/i', $part, $m) === 1) {\n                                $fqcn = trim($m[1]);\n                                $alias = $m[2] ?? basename(str_replace('\\\\', '/', $fqcn));\n                                $imports[$alias] = ltrim($fqcn, '\\\\');\n                            }\n                        }\n                    } elseif (preg_match('/^(?:function\\s+|const\\s+)?([a-zA-Z0-9_\\\\\\\\]+)(?:\\s+as\\s+([a-zA-Z0-9_]+))?$/i', trim($useStatement), $m) === 1) {\n                        $fqcn = trim($m[1]);\n                        $alias = $m[2] ?? basename(str_replace('\\\\', '/', $fqcn));\n                        $imports[$alias] = ltrim($fqcn, '\\\\');\n                    }\n                }\n            }\n\n            self::$fileUseImports[$normalizedFile] = $imports;\n        } catch (\\Throwable $e) {\n            self::$fileUseImports[$normalizedFile] = [];\n        }\n    }\n}\n","/typephp/src/Internal/RuntimeTypeChecker.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Ast\\ScopeCleaner;\nuse TypePHP\\Internal\\Checker\\GeneratorChecker;\nuse TypePHP\\Internal\\Checker\\InlineChecker;\nuse TypePHP\\Internal\\Checker\\ParamChecker;\nuse TypePHP\\Internal\\Checker\\ParamOutChecker;\nuse TypePHP\\Internal\\Checker\\ReturnChecker;\nuse TypePHP\\Internal\\Checker\\SelfOutChecker;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Resolver\\CallerBoundaryResolver;\nuse TypePHP\\Internal\\Util\\Config;\nuse TypePHP\\Internal\\Util\\IgnoreManager;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\nuse TypePHP\\Internal\\Wrapper\\CallableWrapper;\nuse TypePHP\\Internal\\Wrapper\\IterableWrapper;\n\n/**\n * Core runtime type checking engine facade for parameter validation, return type enforcement, and variable tracking.\n */\nfinal class RuntimeTypeChecker\n{\n    private static ?TypeValidatorRegistry $registry = null;\n\n    /**\n     * @var array<string, bool>\n     */\n    public static array $hasMethodTemplatesCache = [];\n\n    /**\n     * 2D Cache for checked static properties: [$className][$propName] => true.\n     *\n     * @var array<string, array<string, true>>\n     */\n    private static array $checkedStaticProperties = [];\n\n    /**\n     * Resets runtime caches.\n     */\n    public static function reset(): void\n    {\n        self::$hasMethodTemplatesCache = [];\n        self::$checkedStaticProperties = [];\n        IgnoreManager::reset();\n        CallerBoundaryResolver::reset();\n        ParamOutChecker::reset();\n        SelfOutChecker::reset();\n    }\n\n    /**\n     * Returns whether TypePHP is globally enabled in configuration.\n     */\n    public static function isEnabled(): bool\n    {\n        return Config::isEnabled();\n    }\n\n    /**\n     * Pre-binds generic template state on a class before its constructor executes.\n     *\n     * @param \\Closure(): mixed $factory\n     */\n    public static function withPendingGeneric(string $typeString, \\Closure $factory, string $file = ''): mixed\n    {\n        if (! Config::isEnabled() || ! Config::isInlineGenericsEnabled()) {\n            return $factory();\n        }\n\n        TemplateManager::pushPendingInstantiation($typeString, $file);\n\n        try {\n            return $factory();\n        } finally {\n            TemplateManager::popPendingInstantiation();\n        }\n    }\n\n    /**\n     * Evaluates inline property validation dynamically based on configuration with zero-allocation 2D caching.\n     */\n    public static function checkStaticProperty(\n        mixed $objectOrClass,\n        string $propName,\n        mixed $value,\n        string $file = '',\n        ?int $line = null\n    ): mixed {\n        if (! Config::isEnabled() || ! Config::isInlinePropertiesEnabled()) {\n            return $value;\n        }\n\n        $className = \\is_object($objectOrClass) ? $objectOrClass::class : (\\is_string($objectOrClass) ? $objectOrClass : '');\n\n        if ($className !== '' && isset(self::$checkedStaticProperties[$className][$propName])) {\n            return $value;\n        }\n\n        if ($className !== '') {\n            self::$checkedStaticProperties[$className][$propName] = true;\n        }\n\n        $res = self::checkProperty($value, $objectOrClass, $propName, $file);\n        if ($res instanceof ErrorMessage) {\n            $typeError = new \\TypePHP\\Exception\\TypeError($res->getMessage());\n\n            throw ErrorFactory::prepareException($typeError, $line, $file !== '' ? $file : null);\n        }\n\n        return $value;\n    }\n\n    /**\n     * Delegates generic template binding for class instances.\n     */\n    public static function bindInstanceFromNode(object $instance, GenericTypeNode $typeNode, string $context = '', bool $forceBind = false): ?ErrorMessage\n    {\n        if (! Config::isEnabled()) {\n            return null;\n        }\n\n        $err = TemplateManager::bindInstanceFromNode($instance, $typeNode, $context, $forceBind);\n\n        if ($err !== null && (IgnoreManager::isCallerIgnored() || CallerBoundaryResolver::shouldBypass($context))) {\n            return null;\n        }\n\n        return $err;\n    }\n\n    /**\n     * Evaluates inline variable validation dynamically based on configuration.\n     */\n    public static function checkVariable(\n        mixed $value,\n        string $typeString,\n        string $varName,\n        string $file,\n        ?string $caller = null,\n        mixed $thisOrClass = null\n    ): mixed {\n        if (! Config::isEnabled()) {\n            return $value;\n        }\n\n        $res = InlineChecker::checkVariable(\n            $value,\n            $typeString,\n            $varName,\n            $file,\n            self::getRegistry(),\n            $caller,\n            $thisOrClass\n        );\n\n        if ($res instanceof ErrorMessage && (IgnoreManager::isCallerIgnored() || CallerBoundaryResolver::shouldBypass($caller ?? ''))) {\n            return $value;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Evaluates class property validation dynamically based on configuration.\n     */\n    public static function checkProperty(mixed $value, mixed $objectOrClass, string $propName, string $file): mixed\n    {\n        $className = \\is_object($objectOrClass) ? $objectOrClass::class : (\\is_string($objectOrClass) ? $objectOrClass : '');\n        if ($className !== '' && isset(InlineChecker::$nullPropertyCache[$className][$propName])) {\n            return $value;\n        }\n\n        if (! Config::isEnabled()) {\n            return $value;\n        }\n\n        $res = InlineChecker::checkProperty($value, $objectOrClass, $propName, $file, self::getRegistry());\n\n        if ($res instanceof ErrorMessage && (IgnoreManager::isCallerIgnored() || CallerBoundaryResolver::shouldBypass($className . '::$' . $propName))) {\n            return $value;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Initialises generic call frames and returns a ScopeCleaner that pops the call frame on destruction.\n     *\n     * @param array<string, mixed> $vars\n     */\n    public static function setupScope(string $function, array $vars, object|string|null $thisOrClass = null): ErrorMessage|ScopeCleaner|null\n    {\n        if (! Config::isEnabled() || ! Config::isParamsEnabled()) {\n            return null;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return null;\n        }\n\n        if ($thisObj !== null && str_ends_with($effectiveFunction, '::__construct')) {\n            TemplateManager::applyPendingInstantiation($thisObj);\n        }\n\n        if (\n            isset(ParamChecker::$noParamContractCache[$function])\n            && ! (self::$hasMethodTemplatesCache[$function] ?? false)\n        ) {\n            return null;\n        }\n\n        $isMagicCall = str_contains($effectiveFunction, '__call');\n\n        $contract = DocblockParser::parse($effectiveFunction);\n        if (! $isMagicCall && ($contract['allParamsUnconstrained'] ?? false)) {\n            return null;\n        }\n\n        $err = ParamChecker::checkParams(\n            $function,\n            $vars,\n            $thisOrClass,\n            self::getRegistry(),\n            $effectiveFunction,\n            $contract\n        );\n\n        if ($err !== null) {\n            if (IgnoreManager::isCallerIgnored()) {\n                return null;\n            }\n\n            TemplateManager::popCallFrame($effectiveFunction);\n\n            return $err;\n        }\n\n        $hasMethodTemplates = self::$hasMethodTemplatesCache[$effectiveFunction] ?? null;\n        if ($hasMethodTemplates === null) {\n            $hasMethodTemplates = self::$hasMethodTemplatesCache[$effectiveFunction] = (\n                (($contract['templates'] ?? []) !== []) || ($contract['returnUsesMethodTemplates'] ?? false)\n            );\n            self::$hasMethodTemplatesCache[$function] = $hasMethodTemplates;\n        }\n\n        return $hasMethodTemplates ? new ScopeCleaner($effectiveFunction) : null;\n    }\n\n    /**\n     * Validates all incoming parameters against the function or method's declared contract.\n     *\n     * @param array<string, mixed> $vars\n     */\n    public static function checkParams(string $function, array $vars, object|string|null $thisOrClass = null): ?ErrorMessage\n    {\n        if (! Config::isEnabled()) {\n            return null;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return null;\n        }\n\n        $err = ParamChecker::checkParams($function, $vars, $thisOrClass, self::getRegistry());\n\n        if ($err !== null && IgnoreManager::isCallerIgnored()) {\n            return null;\n        }\n\n        return $err;\n    }\n\n    /**\n     * Validates a by-reference parameter's post-condition (@param-out) upon exit.\n     */\n    public static function checkParamOut(string $function, string $paramName, mixed $value, object|string|null $thisOrClass = null): ?ErrorMessage\n    {\n        if (! Config::isEnabled() || ! Config::isParamsOutEnabled()) {\n            return null;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return null;\n        }\n\n        $res = ParamOutChecker::checkParamOut($function, $paramName, $value, $thisOrClass, self::getRegistry(), $effectiveFunction);\n\n        if ($res instanceof ErrorMessage && IgnoreManager::isCallerIgnored()) {\n            return null;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Re-types generic template state on $this upon method exit (@self-out, @phpstan-self-out, @psalm-self-out).\n     *\n     * @param array<int|string, mixed>|null $vars\n     */\n    public static function checkSelfOut(string $function, object $thisObj, ?array $vars = []): void\n    {\n        if (! Config::isEnabled() || ! Config::isSelfOutEnabled()) {\n            return;\n        }\n\n        if (isset(SelfOutChecker::$noSelfOutContractCache[$function])) {\n            return;\n        }\n\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisObj, $thisObj);\n\n        if (isset(SelfOutChecker::$noSelfOutContractCache[$effectiveFunction])) {\n            SelfOutChecker::$noSelfOutContractCache[$function] = true;\n\n            return;\n        }\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return;\n        }\n\n        if (IgnoreManager::isCallerIgnored()) {\n            return;\n        }\n\n        $vars ??= [];\n\n        SelfOutChecker::checkSelfOut($function, $thisObj, $vars, self::getRegistry(), $effectiveFunction);\n    }\n\n    /**\n     * Validates a function or method's return value against its declared contract and returns value or ErrorMessage.\n     *\n     * @param array<string, mixed>|null $vars\n     */\n    public static function checkReturn(string $function, mixed $value, object|string|null $thisOrClass = null, ?array $vars = []): mixed\n    {\n        if (! Config::isEnabled() || ! Config::isReturnsEnabled()) {\n            return $value;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return $value;\n        }\n\n        if (isset(ReturnChecker::$noReturnContractCache[$function]) || isset(ReturnChecker::$noReturnContractCache[$effectiveFunction])) {\n            ReturnChecker::$noReturnContractCache[$function] = true;\n\n            return $value;\n        }\n\n        $isMagicCall = str_contains($effectiveFunction, '__call');\n\n        $contract = DocblockParser::parse($effectiveFunction);\n        if (! $isMagicCall && ($contract['returnUnconstrained'] ?? false)) {\n            return $value;\n        }\n\n        $vars ??= [];\n\n        $res = ReturnChecker::checkReturn(\n            $function,\n            $value,\n            $thisOrClass,\n            $vars,\n            self::getRegistry(),\n            [self::class, 'wrapIterable'],\n            $effectiveFunction,\n            $contract\n        );\n\n        if ($res instanceof ErrorMessage && IgnoreManager::isCallerIgnored()) {\n            return $value;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Validates a value sent into a generator via $gen->send() against TSend.\n     */\n    public static function checkSend(string $function, mixed $sendValue, object|string|null $thisOrClass = null): mixed\n    {\n        if (! Config::isEnabled()) {\n            return $sendValue;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return $sendValue;\n        }\n\n        $res = GeneratorChecker::checkSend($function, $sendValue, self::getRegistry(), $thisOrClass);\n\n        if ($res instanceof ErrorMessage && IgnoreManager::isCallerIgnored()) {\n            return $sendValue;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Validates yielded keys and values from a generator function against TKey and TValue.\n     */\n    public static function checkYield(string $function, mixed $key, mixed $value, object|string|null $thisOrClass = null): mixed\n    {\n        if (! Config::isEnabled()) {\n            return $value;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return $value;\n        }\n\n        $res = GeneratorChecker::checkYield($function, $key, $value, self::getRegistry(), $thisOrClass);\n\n        if ($res instanceof ErrorMessage && IgnoreManager::isCallerIgnored()) {\n            return $value;\n        }\n\n        return $res;\n    }\n\n    /**\n     * Wraps a callable parameter to intercept calls and validate inputs/returns dynamically.\n     */\n    public static function wrapCallable(string $function, string $paramName, mixed $callable, object|string|null $thisOrClass = null): mixed\n    {\n        if (! Config::isEnabled()) {\n            return $callable;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return $callable;\n        }\n\n        return CallableWrapper::wrap($function, $paramName, $callable, self::getRegistry(), $thisOrClass);\n    }\n\n    /**\n     * Wraps an iterable or generator parameter to lazily validate items during iteration.\n     */\n    public static function wrapIterable(string $function, string $paramName, mixed $iterable, object|string|null $thisOrClass = null): mixed\n    {\n        if (! Config::isEnabled()) {\n            return $iterable;\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $effectiveFunction = ParamChecker::resolveEffectiveFunction($function, $thisOrClass, $thisObj);\n\n        if (CallerBoundaryResolver::shouldBypass($effectiveFunction)) {\n            return $iterable;\n        }\n\n        return IterableWrapper::wrap($function, $paramName, $iterable, self::getRegistry(), $thisOrClass);\n    }\n\n    /**\n     * Registers a pending clone source object before clone execution.\n     */\n    public static function prepareClone(mixed $original): mixed\n    {\n        if (\\is_object($original)) {\n            TemplateManager::$pendingCloneSource = $original;\n        }\n\n        return $original;\n    }\n\n    /**\n     * Copies generic template bindings from an original object to a cloned object instance.\n     */\n    public static function cloneInstance(mixed $cloned, mixed $original): mixed\n    {\n        if (\\is_object($cloned) && \\is_object($original)) {\n            TemplateManager::copyInstanceBindings($original, $cloned);\n        }\n\n        TemplateManager::$pendingCloneSource = null;\n\n        return $cloned;\n    }\n\n    /**\n     * Infers a TypeNode AST representation from a raw PHP value.\n     */\n    public static function inferTypeFromValue(mixed $value): TypeNode\n    {\n        return TemplateManager::inferTypeFromValue($value);\n    }\n\n    /**\n     * Returns a singleton instance of the TypeValidatorRegistry.\n     */\n    public static function getRegistry(): TypeValidatorRegistry\n    {\n        return self::$registry ??= new TypeValidatorRegistry();\n    }\n}\n","/typephp/src/Internal/Util/ClassNameValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\n/**\n * @internal\n */\nfinal class ClassNameValidator\n{\n    /**\n     * @var array<string, bool>\n     */\n    private static array $validSyntaxCache = [];\n\n    /**\n     * @var array<string, bool>\n     */\n    private static array $validClassStringCache = [];\n\n    public static function reset(): void\n    {\n        self::$validSyntaxCache = [];\n        self::$validClassStringCache = [];\n    }\n\n    /**\n     * Validates whether a given value is a syntactically valid PHP class, interface, trait, or enum identifier,\n     * or a valid anonymous class name registered in memory.\n     */\n    public static function isValid(mixed $name): bool\n    {\n        if (! \\is_string($name) || $name === '') {\n            return false;\n        }\n\n        if (isset(self::$validSyntaxCache[$name])) {\n            return self::$validSyntaxCache[$name];\n        }\n\n        if (str_contains($name, '@anonymous')) {\n            return self::$validSyntaxCache[$name] = class_exists($name, false);\n        }\n\n        $trimmed = ltrim($name, '\\\\');\n        if ($trimmed === '') {\n            return self::$validSyntaxCache[$name] = false;\n        }\n\n        $valid = preg_match('/^[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*(?:\\\\\\\\[a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)*$/', $trimmed) === 1;\n\n        return self::$validSyntaxCache[$name] = $valid;\n    }\n\n    /**\n     * Validates a class-string value:\n     * - Unqualified names (e.g. 'Hello', 'stdClass') MUST physically exist in runtime.\n     * - Qualified names (e.g. 'App\\Models\\User') pass if they exist or match valid qualified class syntax.\n     */\n    public static function isValidClassString(mixed $name): bool\n    {\n        if (! \\is_string($name) || $name === '') {\n            return false;\n        }\n\n        if (isset(self::$validClassStringCache[$name])) {\n            return self::$validClassStringCache[$name];\n        }\n\n        if (! self::isValid($name)) {\n            return self::$validClassStringCache[$name] = false;\n        }\n\n        if (class_exists($name, false) || interface_exists($name, false) || trait_exists($name, false) || enum_exists($name, false)) {\n            return self::$validClassStringCache[$name] = true;\n        }\n\n        if (class_exists($name) || interface_exists($name) || trait_exists($name) || enum_exists($name)) {\n            return self::$validClassStringCache[$name] = true;\n        }\n\n        $trimmed = ltrim($name, '\\\\');\n\n        return self::$validClassStringCache[$name] = str_contains($trimmed, '\\\\');\n    }\n}\n","/typephp/src/Internal/Util/Config.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\nuse TypePHP\\Extension\\ExtensionInterface;\nuse TypePHP\\Internal\\Checker\\ParamChecker;\nuse TypePHP\\Internal\\Checker\\ReturnChecker;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Io\\CacheManager;\nuse TypePHP\\Internal\\Io\\StreamWrapper;\nuse TypePHP\\Internal\\Resolver\\CallerBoundaryResolver;\nuse TypePHP\\Internal\\Resolver\\HierarchyResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\RuntimeTypeChecker;\n\n/**\n * Global configuration manager for loading and dynamically overriding settings.\n *\n * @internal\n */\nfinal class Config\n{\n    /**\n     * Threshold (number of elements) above which Beartype O(1) hybrid random sampling is applied.\n     */\n    public const HYBRID_SAMPLE_THRESHOLD = 128;\n\n    /**\n     * @var array<string, mixed>|null\n     */\n    private static ?array $cachedConfig = null;\n\n    /**\n     * Cached absolute project root path.\n     */\n    private static ?string $projectRoot = null;\n\n    private static bool $enabled = true;\n\n    private static bool $params = true;\n\n    private static bool $returns = true;\n\n    private static bool $strictReturnGenericInvariance = true;\n\n    private static bool $magicProperties = true;\n\n    private static bool $magicMethods = true;\n\n    private static bool $respectIgnoreTags = true;\n\n    private static bool $respectNativeNullability = true;\n\n    private static bool $vendorBoundaryOnly = true;\n\n    private static bool $cacheCheckMtime = true;\n\n    private static bool $paramsOut = true;\n\n    private static bool $selfOut = true;\n\n    private static string $arrayValidation = 'full';\n\n    private static bool $inlineProperties = true;\n\n    private static bool $inlineGenerics = true;\n\n    private static bool $inlineCallables = true;\n\n    private static bool $inlineScalars = true;\n\n    private static bool $inlineArrays = true;\n\n    private static bool $inlineObjects = true;\n\n    private static int $ignoreTraceDepth = 25;\n\n    public static function isEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$enabled;\n    }\n\n    public static function getIgnoreTraceDepth(): int\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$ignoreTraceDepth;\n    }\n\n    public static function isInlinePropertiesEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineProperties;\n    }\n\n    public static function isInlineGenericsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineGenerics;\n    }\n\n    public static function isInlineCallablesEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineCallables;\n    }\n\n    public static function isInlineScalarsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineScalars;\n    }\n\n    public static function isInlineArraysEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineArrays;\n    }\n\n    public static function isInlineObjectsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineObjects;\n    }\n\n    public static function hasActiveInlineChecks(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$inlineGenerics\n            || self::$inlineCallables\n            || self::$inlineScalars\n            || self::$inlineArrays\n            || self::$inlineObjects;\n    }\n\n    public static function isCacheCheckMtimeEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$cacheCheckMtime;\n    }\n\n    public static function isParamsOutEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$params && self::$paramsOut;\n    }\n\n    public static function isSelfOutEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$selfOut;\n    }\n\n    public static function isParamsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$params;\n    }\n\n    public static function isReturnsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$returns;\n    }\n\n    public static function isStrictReturnGenericInvarianceEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$strictReturnGenericInvariance;\n    }\n\n    public static function isMagicPropertiesEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$magicProperties;\n    }\n\n    public static function isMagicMethodsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$magicMethods;\n    }\n\n    public static function isRespectIgnoreTagsEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$respectIgnoreTags;\n    }\n\n    public static function isRespectNativeNullabilityEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$respectNativeNullability;\n    }\n\n    public static function isVendorBoundaryOnlyEnabled(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$vendorBoundaryOnly;\n    }\n\n    public static function isArrayValidationHybrid(): bool\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$arrayValidation === 'hybrid';\n    }\n\n    public static function getArrayValidationStrategy(): string\n    {\n        if (self::$cachedConfig === null) {\n            self::get();\n        }\n\n        return self::$arrayValidation;\n    }\n\n    /**\n     * Locates the project root directory by searching upwards for vendor/autoload.php or composer.json.\n     * Caches the result in memory so the search happens exactly once.\n     */\n    public static function getProjectRoot(?string $startingDir = null): string\n    {\n        if ($startingDir === null && self::$projectRoot !== null) {\n            return self::$projectRoot;\n        }\n\n        $cwd = getcwd();\n        if ($startingDir === null && $cwd !== false) {\n            $realCwd = realpath($cwd) !== false ? realpath($cwd) : $cwd;\n            $normCwd = rtrim(str_replace('\\\\', '/', (string) $realCwd), '/');\n            if (\n                file_exists($normCwd . '/vendor/autoload.php')\n                || file_exists($normCwd . '/composer.json')\n            ) {\n                return self::$projectRoot = $normCwd;\n            }\n        }\n\n        $dir = str_replace('\\\\', '/', $startingDir ?? __DIR__);\n\n        if (str_contains($dir, '/vendor/')) {\n            $vendorPos = strrpos($dir, '/vendor/');\n            if ($vendorPos !== false) {\n                $candidate = substr($dir, 0, $vendorPos);\n                $realCandidate = realpath($candidate) !== false ? realpath($candidate) : $candidate;\n                $normCandidate = rtrim(str_replace('\\\\', '/', (string) $realCandidate), '/');\n                if (file_exists($normCandidate . '/vendor/autoload.php') || file_exists($normCandidate . '/composer.json')) {\n                    return self::$projectRoot = $normCandidate;\n                }\n            }\n        }\n\n        for ($i = 0; $i < 10; $i++) {\n            if (file_exists($dir . '/composer.json') || file_exists($dir . '/vendor/autoload.php')) {\n                $realDir = realpath($dir) !== false ? realpath($dir) : $dir;\n\n                return self::$projectRoot = rtrim(str_replace('\\\\', '/', (string) $realDir), '/');\n            }\n\n            $parent = \\dirname($dir);\n            if ($parent === $dir) {\n                break;\n            }\n            $dir = $parent;\n        }\n\n        $fallback = $cwd !== false ? (realpath($cwd) !== false ? realpath($cwd) : $cwd) : '.';\n\n        return self::$projectRoot = rtrim(str_replace('\\\\', '/', (string) $fallback), '/');\n    }\n\n    /**\n     * Loads and caches global configuration from 'typephp.php', explicitly registered extensions, and base defaults.\n     *\n     * @return array<string, mixed>\n     */\n    public static function get(): array\n    {\n        if (self::$cachedConfig !== null) {\n            return self::$cachedConfig;\n        }\n\n        $defaultConfig = [\n            'enabled' => true,\n            'params' => true,\n            'returns' => true,\n            'params_out' => true,\n            'self_out' => true,\n            'strict_return_generic_invariance' => true,\n            'magic_properties' => true,\n            'magic_methods' => true,\n            'respect_ignore_tags' => true,\n            'ignore_trace_depth' => 25,\n            'respect_native_nullability' => true,\n            'vendor_boundary_only' => true,\n            'array_validation' => 'full',\n            'cache' => true,\n            'cache_dir' => null,\n            'cache_check_mtime' => true,\n            'inline_vars' => [\n                'properties' => true,\n                'generics' => true,\n                'callables' => true,\n                'scalars' => true,\n                'arrays' => true,\n                'objects' => true,\n            ],\n            'include' => ['src/**', 'app/**', 'internals/**', 'tests/**'],\n            'exclude' => ['vendor/**', 'storage/**', 'var/**', 'cache/**'],\n            'extensions' => [],\n            'stubs' => [],\n        ];\n\n        $projectRoot = self::getProjectRoot();\n        $configFile = $projectRoot . '/typephp.php';\n        $userConfig = [];\n\n        if (file_exists($configFile)) {\n            $loadedConfig = require $configFile;\n            if (\\is_array($loadedConfig)) {\n                /** @var array<string, mixed> $userConfig */\n                $userConfig = $loadedConfig;\n            }\n        }\n\n        /** @var array<int, class-string<ExtensionInterface>> $configuredExtensions */\n        $configuredExtensions = \\is_array($userConfig['extensions'] ?? null)\n            ? $userConfig['extensions']\n            : $defaultConfig['extensions'];\n\n        $extensionIncludes = ExtensionManager::loadExtensionIncludes($configuredExtensions);\n        $extensionStubs = ExtensionManager::loadExtensionStubs($configuredExtensions);\n\n        $mergedConfig = self::mergeConfig($defaultConfig, $userConfig);\n\n        /** @var array<int, string> $currentIncludes */\n        $currentIncludes = \\is_array($mergedConfig['include'] ?? null) ? $mergedConfig['include'] : [];\n        /** @var array<int, string> $currentStubs */\n        $currentStubs = \\is_array($mergedConfig['stubs'] ?? null) ? $mergedConfig['stubs'] : [];\n\n        $mergedConfig['include'] = array_values(array_unique([...$currentIncludes, ...$extensionIncludes]));\n        $mergedConfig['stubs'] = array_values(array_unique([...$currentStubs, ...$extensionStubs]));\n\n        self::syncFlags($mergedConfig);\n\n        return self::$cachedConfig = $mergedConfig;\n    }\n\n    /**\n     * Overrides the current configuration at runtime.\n     *\n     * @param array<string, mixed> $config\n     */\n    public static function set(array $config): void\n    {\n        $current = self::$cachedConfig ?? self::get();\n        $mergedConfig = self::mergeConfig($current, $config);\n\n        if (isset($config['extensions']) && \\is_array($config['extensions'])) {\n            /** @var array<int, class-string<ExtensionInterface>> $configuredExtensions */\n            $configuredExtensions = $config['extensions'];\n            $extensionIncludes = ExtensionManager::loadExtensionIncludes($configuredExtensions);\n            $extensionStubs = ExtensionManager::loadExtensionStubs($configuredExtensions);\n\n            /** @var array<int, string> $currentIncludes */\n            $currentIncludes = \\is_array($mergedConfig['include'] ?? null) ? $mergedConfig['include'] : [];\n            /** @var array<int, string> $currentStubs */\n            $currentStubs = \\is_array($mergedConfig['stubs'] ?? null) ? $mergedConfig['stubs'] : [];\n\n            $mergedConfig['include'] = array_values(array_unique([...$currentIncludes, ...$extensionIncludes]));\n            $mergedConfig['stubs'] = array_values(array_unique([...$currentStubs, ...$extensionStubs]));\n        }\n\n        self::$cachedConfig = $mergedConfig;\n        self::syncFlags($mergedConfig);\n\n        DocblockParser::reset();\n        ParamChecker::reset();\n        ReturnChecker::reset();\n        FileFilter::reset();\n        PathMatcher::reset();\n        StreamWrapper::reset();\n        StubManager::reset();\n        SpecialTypeResolver::reset();\n        CallerBoundaryResolver::reset();\n        CacheManager::reset();\n        IgnoreManager::reset();\n        RuntimeTypeChecker::reset();\n    }\n\n    /**\n     * Merges user configuration over base defaults:\n     * - Associative dictionaries (inline_vars) are merged recursively.\n     * - Sequential lists (include, exclude, extensions, stubs) are REPLACED wholesale when defined.\n     * - Scalars / booleans / strings are overwritten.\n     *\n     * @param array<string, mixed> $base\n     * @param array<string, mixed> $overrides\n     *\n     * @return array<string, mixed>\n     */\n    private static function mergeConfig(array $base, array $overrides): array\n    {\n        $merged = $base;\n\n        foreach ($overrides as $key => $value) {\n            if ($key === 'inline_vars' && \\is_array($value) && isset($base['inline_vars']) && \\is_array($base['inline_vars'])) {\n                /** @var array<string, bool> $baseInlineVars */\n                $baseInlineVars = $base['inline_vars'];\n                /** @var array<string, bool> $overrideInlineVars */\n                $overrideInlineVars = $value;\n                $merged['inline_vars'] = [...$baseInlineVars, ...$overrideInlineVars];\n            } elseif (\\in_array($key, ['include', 'exclude', 'extensions', 'stubs'], true) && \\is_array($value)) {\n                $merged[$key] = array_values($value);\n            } else {\n                $merged[$key] = $value;\n            }\n        }\n\n        return $merged;\n    }\n\n    /**\n     * Resets the configuration cache. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$cachedConfig = null;\n        self::$projectRoot = null;\n        self::$enabled = true;\n        self::$params = true;\n        self::$returns = true;\n        self::$selfOut = true;\n        self::$strictReturnGenericInvariance = true;\n        self::$magicProperties = true;\n        self::$magicMethods = true;\n        self::$respectIgnoreTags = true;\n        self::$ignoreTraceDepth = 25;\n        self::$respectNativeNullability = true;\n        self::$vendorBoundaryOnly = true;\n        self::$arrayValidation = 'full';\n        self::$cacheCheckMtime = true;\n        self::$paramsOut = true;\n        self::$inlineProperties = true;\n        self::$inlineGenerics = true;\n        self::$inlineCallables = true;\n        self::$inlineScalars = true;\n        self::$inlineArrays = true;\n        self::$inlineObjects = true;\n\n        DocblockParser::reset();\n        ParamChecker::reset();\n        ReturnChecker::reset();\n        TemplateManager::reset();\n        HierarchyResolver::reset();\n        FileFilter::reset();\n        PathMatcher::reset();\n        StreamWrapper::reset();\n        StubManager::reset();\n        SpecialTypeResolver::reset();\n        CallerBoundaryResolver::reset();\n        CacheManager::reset();\n        IgnoreManager::reset();\n        RuntimeTypeChecker::reset();\n    }\n\n    /**\n     * Synchronizes cached static boolean flags for fast O(1) checking.\n     *\n     * @param array<string, mixed> $config\n     */\n    private static function syncFlags(array $config): void\n    {\n        self::$enabled = (bool) ($config['enabled'] ?? true);\n        self::$params = (bool) ($config['params'] ?? true);\n        self::$paramsOut = (bool) ($config['params_out'] ?? true);\n        self::$selfOut = (bool) ($config['self_out'] ?? true);\n        self::$returns = (bool) ($config['returns'] ?? true);\n        self::$strictReturnGenericInvariance = (bool) ($config['strict_return_generic_invariance'] ?? true);\n        self::$magicProperties = (bool) ($config['magic_properties'] ?? true);\n        self::$magicMethods = (bool) ($config['magic_methods'] ?? true);\n        self::$respectIgnoreTags = (bool) ($config['respect_ignore_tags'] ?? true);\n        self::$ignoreTraceDepth = isset($config['ignore_trace_depth']) && is_numeric($config['ignore_trace_depth']) && (int) $config['ignore_trace_depth'] > 0\n            ? (int) $config['ignore_trace_depth']\n            : 25;\n        self::$respectNativeNullability = (bool) ($config['respect_native_nullability'] ?? true);\n        self::$vendorBoundaryOnly = (bool) ($config['vendor_boundary_only'] ?? true);\n        self::$arrayValidation = \\is_string($config['array_validation'] ?? null) ? $config['array_validation'] : 'full';\n        self::$cacheCheckMtime = (bool) ($config['cache_check_mtime'] ?? true);\n        $inline = \\is_array($config['inline_vars'] ?? null) ? $config['inline_vars'] : [];\n        self::$inlineProperties = (bool) ($inline['properties'] ?? true);\n        self::$inlineGenerics = (bool) ($inline['generics'] ?? true);\n        self::$inlineCallables = (bool) ($inline['callables'] ?? true);\n        self::$inlineScalars = (bool) ($inline['scalars'] ?? true);\n        self::$inlineArrays = (bool) ($inline['arrays'] ?? true);\n        self::$inlineObjects = (bool) ($inline['objects'] ?? true);\n    }\n}\n","/typephp/src/Internal/Util/ExtensionManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\nuse TypePHP\\Extension\\ExtensionInterface;\n\n/**\n * Loads explicitly registered TypePHP extensions from user configuration.\n */\nfinal class ExtensionManager\n{\n    /**\n     * Safely loads and merges whitelist include paths from explicitly configured extensions.\n     * Extensions are structurally restricted to 'include' and 'stubs' only.\n     * Exclude authority belongs strictly to the end-user's local typephp.php file.\n     *\n     * @param array<int, class-string<ExtensionInterface>> $configuredExtensions\n     *\n     * @return array<int, string>\n     */\n    public static function loadExtensionIncludes(array $configuredExtensions = []): array\n    {\n        $extensionIncludes = [];\n        $uniqueExtensions = array_unique($configuredExtensions);\n\n        foreach ($uniqueExtensions as $extensionClass) {\n            if (\\is_string($extensionClass) && class_exists($extensionClass) && is_a($extensionClass, ExtensionInterface::class, allow_string: true)) {\n                /** @var ExtensionInterface $instance */\n                $instance = new $extensionClass();\n                $config = $instance->getConfig();\n\n                // Extensions can ONLY append include paths (whitelisting)\n                if (isset($config['include']) && \\is_array($config['include'])) {\n                    foreach ($config['include'] as $inc) {\n                        if (\\is_string($inc) && $inc !== '') {\n                            $extensionIncludes[] = $inc;\n                        }\n                    }\n                }\n            }\n        }\n\n        return array_unique($extensionIncludes);\n    }\n\n    /**\n     * Safely loads and merges stub file paths from explicitly configured extensions.\n     *\n     * @param array<int, class-string<ExtensionInterface>> $configuredExtensions\n     *\n     * @return array<int, string>\n     */\n    public static function loadExtensionStubs(array $configuredExtensions = []): array\n    {\n        $extensionStubs = [];\n        $uniqueExtensions = array_unique($configuredExtensions);\n\n        foreach ($uniqueExtensions as $extensionClass) {\n            if (\\is_string($extensionClass) && class_exists($extensionClass) && is_a($extensionClass, ExtensionInterface::class, allow_string: true)) {\n                /** @var ExtensionInterface $instance */\n                $instance = new $extensionClass();\n                $config = $instance->getConfig();\n\n                if (isset($config['stubs']) && \\is_array($config['stubs'])) {\n                    foreach ($config['stubs'] as $stub) {\n                        if (\\is_string($stub) && $stub !== '') {\n                            $extensionStubs[] = $stub;\n                        }\n                    }\n                }\n            }\n        }\n\n        return array_unique($extensionStubs);\n    }\n}\n","/typephp/src/Internal/Util/FileFilter.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\n/**\n * @internal Checks file paths against vendor directories, file extensions, and user-configured include/exclude globs.\n */\nfinal class FileFilter\n{\n    /**\n     * In-memory cache of boolean exclusion results keyed by normalized file path.\n     *\n     * @var array<string, bool>\n     */\n    private static array $pathFilterCache = [];\n\n    /**\n     * Resets the path decision cache and pre-compiled regex patterns. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$pathFilterCache = [];\n        PathMatcher::reset();\n    }\n\n    /**\n     * Determines whether a given file path is excluded from contract inheritance.\n     * Non-PHP files and excluded paths return true.\n     */\n    public static function isFileExcluded(string|false|null $fileName): bool\n    {\n        if ($fileName === null || $fileName === false || $fileName === '') {\n            return false;\n        }\n\n        $normalizedPath = PathMatcher::normalizePath($fileName);\n\n        if (isset(self::$pathFilterCache[$normalizedPath])) {\n            return self::$pathFilterCache[$normalizedPath];\n        }\n\n        // Non-PHP files are always excluded from PHPDoc contract processing\n        if (! str_ends_with(strtolower($normalizedPath), '.php')) {\n            return self::$pathFilterCache[$normalizedPath] = true;\n        }\n\n        if (PathMatcher::isCachePath($normalizedPath)) {\n            return self::$pathFilterCache[$normalizedPath] = true;\n        }\n\n        $config = Config::get();\n        /** @var array<int, string> $includes */\n        $includes = \\is_array($config['include'] ?? null) ? $config['include'] : ['**'];\n        /** @var array<int, string> $excludes */\n        $excludes = \\is_array($config['exclude'] ?? null) ? $config['exclude'] : ['vendor/**', 'storage/**', 'var/**', 'cache/**'];\n\n        $isIncluded = PathMatcher::isPathIncluded($normalizedPath, $includes, $excludes, $fileName);\n\n        return self::$pathFilterCache[$normalizedPath] = ! $isIncluded;\n    }\n}\n","/typephp/src/Internal/Util/IgnoreManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\nuse ReflectionClass;\nuse ReflectionFunction;\n\n/**\n * @internal High-performance manager for resolving file-level and caller-level @typephp-ignore tags.\n */\nfinal class IgnoreManager\n{\n    /**\n     * In-memory cache for caller method ignore decisions (ClassName::method => bool).\n     *\n     * @var array<string, bool>\n     */\n    private static array $callerCache = [];\n\n    /**\n     * In-memory registry of files marked with @typephp-ignore-file.\n     *\n     * @var array<string, bool>\n     */\n    private static array $fileCache = [];\n\n    /**\n     * Resets all ignore caches.\n     */\n    public static function reset(): void\n    {\n        self::$callerCache = [];\n        self::$fileCache = [];\n    }\n\n    /**\n     * Registers a file as ignored at the StreamWrapper level during file load.\n     */\n    public static function registerIgnoredFile(string $filePath): void\n    {\n        if ($filePath === '') {\n            return;\n        }\n\n        $normalized = str_replace('\\\\', '/', $filePath);\n        self::$fileCache[$normalized] = true;\n    }\n\n    /**\n     * Fast O(1) check if a file has @typephp-ignore-file in memory.\n     */\n    public static function isFileIgnored(string $filePath): bool\n    {\n        if ($filePath === '' || self::$fileCache === []) {\n            return false;\n        }\n\n        $normalized = str_replace('\\\\', '/', $filePath);\n\n        return self::$fileCache[$normalized] ?? false;\n    }\n\n    /**\n     * Determines whether the calling method, function, or file has @typephp-ignore annotations.\n     * Only executed when a type validation failure occurs.\n     */\n    public static function isCallerIgnored(?string $callerClass = null, ?string $callerFunction = null): bool\n    {\n        if (! Config::isRespectIgnoreTagsEnabled()) {\n            return false;\n        }\n\n        if ($callerClass !== null && $callerFunction !== null) {\n            $key = $callerClass . '::' . $callerFunction;\n            if (isset(self::$callerCache[$key])) {\n                return self::$callerCache[$key];\n            }\n\n            return self::$callerCache[$key] = self::checkMethodIgnored($callerClass, $callerFunction);\n        }\n\n        if ($callerFunction !== null) {\n            if (isset(self::$callerCache[$callerFunction])) {\n                return self::$callerCache[$callerFunction];\n            }\n\n            return self::$callerCache[$callerFunction] = self::checkFunctionIgnored($callerFunction);\n        }\n\n        $depth = Config::getIgnoreTraceDepth();\n        $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, $depth);\n\n        for ($i = 1; $i < \\count($trace); $i++) {\n            $frame = $trace[$i];\n            $class = $frame['class'] ?? '';\n            $function = $frame['function'];\n            $file = $frame['file'] ?? '';\n\n            // Skip internal library frames and test runner framework internals\n            if (\n                $class !== '' && (\n                    str_starts_with($class, 'TypePHP\\\\Internal\\\\')\n                    || $class === 'TypePHP\\\\TypePHP'\n                    || str_starts_with($class, 'PHPUnit\\\\')\n                    || str_starts_with($class, 'Pest\\\\')\n                    || str_starts_with($class, 'P\\\\')\n                )\n            ) {\n                continue;\n            }\n\n            if (str_contains($function, '__pest_')) {\n                continue;\n            }\n\n            if ($class === '' && \\in_array($function, ['call_user_func', 'call_user_func_array'], true)) {\n                continue;\n            }\n\n            if ($file !== '' && self::isFileIgnored($file)) {\n                return true;\n            }\n\n            if ($class !== '') {\n                $key = $class . '::' . $function;\n                if (isset(self::$callerCache[$key])) {\n                    if (self::$callerCache[$key]) {\n                        return true;\n                    }\n\n                    continue;\n                }\n\n                if (self::checkMethodIgnored($class, $function)) {\n                    return self::$callerCache[$key] = true;\n                }\n\n                self::$callerCache[$key] = false;\n            } elseif (! str_contains($function, '{closure}')) {\n                if (isset(self::$callerCache[$function])) {\n                    if (self::$callerCache[$function]) {\n                        return true;\n                    }\n\n                    continue;\n                }\n\n                if (self::checkFunctionIgnored($function)) {\n                    return self::$callerCache[$function] = true;\n                }\n\n                self::$callerCache[$function] = false;\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Checks if a docblock contains a standalone @typephp-ignore or @typephp-disable tag.\n     */\n    public static function hasIgnoreDocTag(string|false|null $doc): bool\n    {\n        if ($doc === null || $doc === false || $doc === '') {\n            return false;\n        }\n\n        if (! str_contains($doc, '@typephp-ignore') && ! str_contains($doc, '@typephp-disable')) {\n            return false;\n        }\n\n        return (bool) preg_match(\n            '/(?:^\\s*\\*\\s*|\\/\\*\\*\\s*|(?:\\/\\/|#)\\s*)@(typephp-ignore|typephp-disable)(?:\\s|\\*\\/|$)/m',\n            $doc\n        );\n    }\n\n    private static function checkMethodIgnored(string $class, string $method): bool\n    {\n        if (StubManager::hasMethodStub($class, $method)) {\n            $stubDoc = StubManager::getMethodDoc($class, $method);\n            if (self::hasIgnoreDocTag($stubDoc)) {\n                return true;\n            }\n        }\n\n        if (StubManager::hasClassStub($class)) {\n            $classStubDoc = StubManager::getClassDoc($class);\n            if (self::hasIgnoreDocTag($classStubDoc)) {\n                return true;\n            }\n        }\n\n        if (! class_exists($class) && ! trait_exists($class) && ! interface_exists($class) && ! enum_exists($class)) {\n            return false;\n        }\n\n        /** @var class-string<object> $class */\n        $refClass = new ReflectionClass($class);\n\n        if ($refClass->hasMethod($method)) {\n            $refMethod = $refClass->getMethod($method);\n            if (self::hasIgnoreDocTag($refMethod->getDocComment())) {\n                return true;\n            }\n        }\n\n        return self::hasIgnoreDocTag($refClass->getDocComment());\n    }\n\n    private static function checkFunctionIgnored(string $function): bool\n    {\n        if (StubManager::hasFunctionStub($function)) {\n            $stubDoc = StubManager::getFunctionDoc($function);\n            if (self::hasIgnoreDocTag($stubDoc)) {\n                return true;\n            }\n        }\n\n        if (! \\function_exists($function)) {\n            return false;\n        }\n\n        $refFunc = new ReflectionFunction($function);\n\n        return self::hasIgnoreDocTag($refFunc->getDocComment());\n    }\n}\n","/typephp/src/Internal/Util/PathMatcher.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\nuse TypePHP\\Internal\\Io\\CacheManager;\n\nrequire_once __DIR__ . '/../Io/CacheManager.php';\n\n/**\n * Centralized utility for path normalization, glob compilation, vendor isolation, and specificity matching.\n *\n * @internal\n */\nfinal class PathMatcher\n{\n    /**\n     * Cache for compiled include regexes per base directory.\n     *\n     * @var array<string, array<int, array{pattern: string, len: int, regex: string}>>\n     */\n    private static array $compiledIncludesCache = [];\n\n    /**\n     * Cache for compiled exclude regexes per base directory.\n     *\n     * @var array<string, array<int, array{pattern: string, len: int, regex: string}>>\n     */\n    private static array $compiledExcludesCache = [];\n\n    /**\n     * Cache for include prefix lookup decisions.\n     *\n     * @var array<string, bool>\n     */\n    private static array $includePrefixCache = [];\n\n    /**\n     * Cached normalized cache directory path.\n     */\n    private static ?string $cachedCacheDir = null;\n\n    /**\n     * Cached TypePHP library src directory path.\n     */\n    private static ?string $cachedLibSrcDir = null;\n\n    /**\n     * Resets compiled pattern, prefix, and directory caches.\n     */\n    public static function reset(): void\n    {\n        self::$compiledIncludesCache = [];\n        self::$compiledExcludesCache = [];\n        self::$includePrefixCache = [];\n        self::$cachedCacheDir = null;\n        self::$cachedLibSrcDir = null;\n        CacheManager::reset();\n    }\n\n    /**\n     * Normalizes directory separators to forward slashes.\n     */\n    public static function normalizePath(string|false|null $path): string\n    {\n        if ($path === null || $path === false || $path === '') {\n            return '';\n        }\n\n        return str_replace('\\\\', '/', $path);\n    }\n\n    /**\n     * Collapses relative directory traversals (..) into canonical paths.\n     * Preserves leading root slashes, Windows drive letters, and root boundaries.\n     */\n    public static function canonicalizePath(string $path): string\n    {\n        $path = str_replace('\\\\', '/', $path);\n        if (! str_contains($path, '..') && ! str_contains($path, '/.')) {\n            return $path;\n        }\n\n        $parts = explode('/', $path);\n        $absolutes = [];\n\n        foreach ($parts as $part) {\n            if ($part === '.' || ($part === '' && \\count($absolutes) > 0)) {\n                continue;\n            }\n\n            if ($part === '') {\n                $absolutes[] = '';\n\n                continue;\n            }\n\n            if ($part === '..') {\n                $last = end($absolutes);\n                $isDriveLetter = \\is_string($last) && preg_match('/^[a-zA-Z]:$/', $last) === 1;\n\n                if (\\count($absolutes) > 0 && $last !== '..' && $last !== '' && ! $isDriveLetter) {\n                    array_pop($absolutes);\n                } elseif (\\count($absolutes) === 0 || $last === '..') {\n                    $absolutes[] = '..';\n                }\n            } else {\n                $absolutes[] = $part;\n            }\n        }\n\n        if ($absolutes === ['']) {\n            return '/';\n        }\n\n        return implode('/', $absolutes);\n    }\n\n    /**\n     * Determines whether a given path is located within a vendor directory.\n     */\n    public static function isVendorPath(string $normalizedPath, string $rawPath = ''): bool\n    {\n        $canon = self::canonicalizePath($normalizedPath);\n        $canonRaw = $rawPath !== '' ? self::canonicalizePath(self::normalizePath($rawPath)) : '';\n\n        return str_starts_with($canon, 'vendor/')\n            || str_contains($canon, '/vendor/')\n            || ($canonRaw !== '' && (str_starts_with($canonRaw, 'vendor/') || str_contains($canonRaw, '/vendor/')));\n    }\n\n    /**\n     * Determines whether a given path belongs to an immutable, static source code repository.\n     */\n    public static function isStaticSourcePath(string $normalizedPath): bool\n    {\n        $canon = self::canonicalizePath($normalizedPath);\n\n        if (self::isDynamicWritablePath($canon)) {\n            return false;\n        }\n\n        if (\n            str_contains($canon, '/tests/') || str_starts_with($canon, 'tests/')\n            || str_contains($canon, '/Fixtures/') || str_contains($canon, '/fixtures/')\n            || str_contains($canon, '/tmp/') || str_contains($canon, '/install/')\n        ) {\n            return false;\n        }\n\n        if (str_starts_with($canon, 'vendor/') || str_contains($canon, '/vendor/')) {\n            return true;\n        }\n\n        if (str_starts_with($canon, 'src/') || str_contains($canon, '/src/')) {\n            return true;\n        }\n\n        if (str_starts_with($canon, 'app/') || str_contains($canon, '/app/')) {\n            return true;\n        }\n\n        if (str_starts_with($canon, 'lib/') || str_contains($canon, '/lib/')) {\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Determines whether a given path is within the TypePHP cache directory.\n     */\n    public static function isCachePath(string $normalizedPath): bool\n    {\n        if (self::$cachedCacheDir === null) {\n            self::$cachedCacheDir = rtrim(self::normalizePath(CacheManager::getCacheDir()), '/') . '/';\n        }\n\n        return str_starts_with(self::canonicalizePath($normalizedPath), self::$cachedCacheDir);\n    }\n\n    /**\n     * Determines whether a path belongs to TypePHP's internal engine source files.\n     */\n    public static function isLibraryInternal(string $normalizedPath): bool\n    {\n        if (self::$cachedLibSrcDir === null) {\n            $parentDir = realpath(\\dirname(__DIR__, 2));\n            self::$cachedLibSrcDir = $parentDir !== false ? rtrim(self::normalizePath($parentDir), '/') . '/' : '';\n        }\n\n        $libSrcDir = self::$cachedLibSrcDir;\n        if ($libSrcDir === '') {\n            return false;\n        }\n\n        $canon = self::canonicalizePath($normalizedPath);\n        $lowerCanon = strtolower($canon);\n        $lowerLibSrcDir = strtolower($libSrcDir);\n\n        if (str_contains($lowerLibSrcDir, '/vendor/')) {\n            return str_starts_with($lowerCanon, $lowerLibSrcDir);\n        }\n\n        if (str_starts_with($lowerCanon, $lowerLibSrcDir)) {\n            $internalDirs = [\n                $lowerLibSrcDir . 'internal/',\n                $lowerLibSrcDir . 'extension/',\n                $lowerLibSrcDir . 'exception/',\n                $lowerLibSrcDir . 'typephp.php',\n                $lowerLibSrcDir . 'bootstrap.php',\n            ];\n\n            foreach ($internalDirs as $dir) {\n                if (str_starts_with($lowerCanon, $dir)) {\n                    return true;\n                }\n            }\n        }\n\n        return false;\n    }\n\n    /**\n     * Fast-checks if an include glob list contains any pattern matching a given prefix.\n     *\n     * @param array<int, string> $includes\n     */\n    public static function hasIncludeMatchingPrefix(string $prefix, array $includes): bool\n    {\n        $cacheKey = $prefix . '|' . implode(',', $includes);\n        if (isset(self::$includePrefixCache[$cacheKey])) {\n            return self::$includePrefixCache[$cacheKey];\n        }\n\n        foreach ($includes as $inc) {\n            if (\\is_string($inc)) {\n                $norm = str_replace('\\\\', '/', trim($inc));\n                if (str_starts_with($norm, $prefix) || str_contains($norm, '/' . $prefix)) {\n                    return self::$includePrefixCache[$cacheKey] = true;\n                }\n            }\n        }\n\n        return self::$includePrefixCache[$cacheKey] = false;\n    }\n\n    /**\n     * Determines whether a directory path is a dynamic writable cache, log, or storage directory.\n     */\n    public static function isDynamicWritablePath(string $normalizedPath): bool\n    {\n        $canon = self::canonicalizePath($normalizedPath);\n\n        return str_contains($canon, '/var/cache/') || str_starts_with($canon, 'var/cache/')\n            || str_contains($canon, '/var/log/') || str_starts_with($canon, 'var/log/')\n            || str_contains($canon, '/storage/') || str_starts_with($canon, 'storage/')\n            || str_contains($canon, '/cache/') || str_starts_with($canon, 'cache/');\n    }\n\n    /**\n     * High-speed string pre-filter to reject non-application paths before executing regex matching.\n     */\n    public static function mayPathBeIncluded(string $normalizedPath): bool\n    {\n        $canon = self::canonicalizePath($normalizedPath);\n\n        if (str_contains($canon, '/node_modules/') || str_starts_with($canon, 'node_modules/')) {\n            return false;\n        }\n\n        if (self::isCachePath($canon)) {\n            return false;\n        }\n\n        $config = Config::get();\n        /** @var array<int, string> $includes */\n        $includes = \\is_array($config['include'] ?? null) ? $config['include'] : ['**'];\n        /** @var array<int, string> $excludes */\n        $excludes = \\is_array($config['exclude'] ?? null) ? $config['exclude'] : [];\n\n        if (str_contains($canon, '/vendor/') || str_starts_with($canon, 'vendor/')) {\n            if (! self::hasIncludeMatchingPrefix('vendor/', $includes)) {\n                return false;\n            }\n        }\n\n        $isSystemVar = str_starts_with($canon, '/var/') || str_starts_with($canon, '/private/var/');\n        $canonAfterSystemVar = str_starts_with($canon, '/private/var/')\n            ? substr($canon, 12)\n            : (str_starts_with($canon, '/var/') ? substr($canon, 4) : $canon);\n\n        if (\n            str_starts_with($canon, 'var/')\n            || (! $isSystemVar && str_contains($canon, '/var/'))\n            || ($isSystemVar && str_contains($canonAfterSystemVar, '/var/'))\n        ) {\n            if (! self::hasIncludeMatchingPrefix('var/', $includes)) {\n                return false;\n            }\n        }\n\n        if (str_contains($canon, '/storage/') || str_starts_with($canon, 'storage/')) {\n            if (! self::hasIncludeMatchingPrefix('storage/', $includes)) {\n                return false;\n            }\n        }\n\n        if (str_contains($canon, '/tests/') || str_starts_with($canon, 'tests/')) {\n            if (! self::hasIncludeMatchingPrefix('tests/', $includes)) {\n                return false;\n            }\n        }\n\n        if (str_contains($canon, '/Migration/') || str_contains($canon, '/migration/')) {\n            if (self::hasIncludeMatchingPrefix('Migration', $excludes) || self::hasIncludeMatchingPrefix('migration', $excludes)) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n    /**\n     * Converts a glob pattern into an absolute anchored regex pattern.\n     */\n    public static function compileGlobToRegex(string $glob, string $baseDir): string\n    {\n        $glob = self::normalizePath(trim($glob));\n        $isAbsolute = str_starts_with($glob, '/') || (bool) preg_match('#^[a-zA-Z]:/#', $glob);\n\n        if ($isAbsolute) {\n            $regex = preg_quote($glob, '#');\n            $regex = str_replace(['\\*\\*', '\\*'], ['.*', '[^/]*'], $regex);\n            $pattern = '^' . $regex . '$';\n        } elseif ($glob === '*' || $glob === '**') {\n            $pattern = '.*$';\n        } elseif (str_starts_with($glob, '**/')) {\n            $subRegex = preg_quote(substr($glob, 3), '#');\n            $subRegex = str_replace(['\\*\\*', '\\*'], ['.*', '[^/]*'], $subRegex);\n            $pattern = '(^|.*\\/)' . $subRegex . '$';\n        } else {\n            $regex = preg_quote($glob, '#');\n            $regex = str_replace(['\\*\\*', '\\*'], ['.*', '[^/]*'], $regex);\n            $pattern = '(^' . preg_quote($baseDir . '/', '#') . '|^)' . $regex . '$';\n        }\n\n        return '#' . $pattern . '#i';\n    }\n\n    /**\n     * Evaluates path specificity against include and exclude globs.\n     *\n     * @param array<int, string> $includeGlobs\n     * @param array<int, string> $excludeGlobs\n     */\n    public static function isPathIncluded(\n        string $normalizedPath,\n        array $includeGlobs,\n        array $excludeGlobs,\n        string $rawPath = '',\n        ?string $baseDir = null\n    ): bool {\n        $baseDir = $baseDir !== null ? self::normalizePath($baseDir) : Config::getProjectRoot();\n        $normalizedPath = self::canonicalizePath($normalizedPath);\n        $normalizedRaw = $rawPath !== '' ? self::canonicalizePath(self::normalizePath($rawPath)) : '';\n\n        $includes = self::getCompiledPatterns($includeGlobs, $baseDir, 'include');\n        $excludes = self::getCompiledPatterns($excludeGlobs, $baseDir, 'exclude');\n\n        $isVendor = self::isVendorPath($normalizedPath, $normalizedRaw);\n        if ($isVendor) {\n            $hasExplicitVendorWhitelist = false;\n            foreach ($includes as $compiled) {\n                $isVendorPattern = self::isVendorPath($compiled['pattern']) || str_starts_with($compiled['pattern'], 'vendor/') || str_contains($compiled['pattern'], '/vendor/');\n\n                if (\n                    $isVendorPattern &&\n                    (preg_match($compiled['regex'], $normalizedPath) === 1 || ($normalizedRaw !== '' && preg_match($compiled['regex'], $normalizedRaw) === 1))\n                ) {\n                    $hasExplicitVendorWhitelist = true;\n\n                    break;\n                }\n            }\n\n            if (! $hasExplicitVendorWhitelist) {\n                return false;\n            }\n        }\n\n        $longestIncludeMatch = 0;\n        foreach ($includes as $compiled) {\n            $isExplicitVendorInclude = self::isVendorPath($compiled['pattern']) || str_starts_with($compiled['pattern'], 'vendor/') || str_contains($compiled['pattern'], '/vendor/');\n            $isWildcard = ($compiled['pattern'] === '*' || $compiled['pattern'] === '**');\n\n            if ($isVendor && ! $isExplicitVendorInclude && ! $isWildcard) {\n                continue;\n            }\n\n            if (preg_match($compiled['regex'], $normalizedPath) === 1 || ($normalizedRaw !== '' && preg_match($compiled['regex'], $normalizedRaw) === 1)) {\n                $longestIncludeMatch = max($longestIncludeMatch, $compiled['len']);\n            }\n        }\n\n        if ($longestIncludeMatch === 0) {\n            return false;\n        }\n\n        $longestExcludeMatch = 0;\n        foreach ($excludes as $compiled) {\n            if (preg_match($compiled['regex'], $normalizedPath) === 1 || ($normalizedRaw !== '' && preg_match($compiled['regex'], $normalizedRaw) === 1)) {\n                $longestExcludeMatch = max($longestExcludeMatch, $compiled['len']);\n            }\n        }\n\n        return $longestIncludeMatch > $longestExcludeMatch;\n    }\n\n    /**\n     * @param array<int, string> $globs\n     *\n     * @return array<int, array{pattern: string, len: int, regex: string}>\n     */\n    private static function getCompiledPatterns(array $globs, string $baseDir, string $type): array\n    {\n        $cacheKey = $baseDir . '|' . implode(',', $globs);\n\n        if ($type === 'include' && isset(self::$compiledIncludesCache[$cacheKey])) {\n            return self::$compiledIncludesCache[$cacheKey];\n        }\n\n        if ($type === 'exclude' && isset(self::$compiledExcludesCache[$cacheKey])) {\n            return self::$compiledExcludesCache[$cacheKey];\n        }\n\n        $compiled = [];\n        foreach ($globs as $pattern) {\n            if (\\is_string($pattern)) {\n                $trimmed = trim($pattern);\n                $compiled[] = [\n                    'pattern' => $trimmed,\n                    'len' => \\strlen($trimmed),\n                    'regex' => self::compileGlobToRegex($trimmed, $baseDir),\n                ];\n            }\n        }\n\n        if ($type === 'include') {\n            return self::$compiledIncludesCache[$cacheKey] = $compiled;\n        }\n\n        return self::$compiledExcludesCache[$cacheKey] = $compiled;\n    }\n}\n","/typephp/src/Internal/Util/StubManager.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Util;\n\nuse FilesystemIterator;\nuse PhpParser\\Node;\nuse RecursiveDirectoryIterator;\nuse RecursiveIteratorIterator;\nuse SplFileInfo;\nuse Throwable;\nuse TypePHP\\Internal\\Io\\StreamWrapper;\n\n/**\n * @internal Indexes and resolves DocBlock stub overrides for third-party classes, methods, properties, and functions.\n */\nfinal class StubManager\n{\n    private static bool $initialized = false;\n\n    /**\n     * @var array<string, string> ClassName::methodName => DocCommentText\n     */\n    private static array $methodStubs = [];\n\n    /**\n     * @var array<string, string> ClassName::$propertyName => DocCommentText\n     */\n    private static array $propertyStubs = [];\n\n    /**\n     * @var array<string, string> ClassName => ClassDocCommentText\n     */\n    private static array $classStubs = [];\n\n    /**\n     * @var array<string, string> functionName => DocCommentText\n     */\n    private static array $functionStubs = [];\n\n    /**\n     * Resets the indexed stub cache. Useful for test isolation.\n     */\n    public static function reset(): void\n    {\n        self::$initialized = false;\n        self::$methodStubs = [];\n        self::$propertyStubs = [];\n        self::$classStubs = [];\n        self::$functionStubs = [];\n    }\n\n    /**\n     * Initializes and indexes stub files configured in typephp.php and registered extensions.\n     */\n    public static function init(): void\n    {\n        if (self::$initialized) {\n            return;\n        }\n\n        self::$initialized = true;\n        $config = Config::get();\n        $rawStubs = $config['stubs'] ?? [];\n\n        /** @var array<int, string> $stubGlobs */\n        $stubGlobs = \\is_array($rawStubs) ? array_filter($rawStubs, 'is_string') : [];\n\n        if (\\count($stubGlobs) === 0) {\n            return;\n        }\n\n        self::loadStubFiles($stubGlobs);\n    }\n\n    public static function getMethodDoc(string $className, string $methodName): ?string\n    {\n        self::init();\n\n        return self::$methodStubs[$className . '::' . $methodName] ?? null;\n    }\n\n    public static function getPropertyDoc(string $className, string $propertyName): ?string\n    {\n        self::init();\n\n        return self::$propertyStubs[$className . '::$' . $propertyName] ?? null;\n    }\n\n    public static function getClassDoc(string $className): ?string\n    {\n        self::init();\n\n        return self::$classStubs[$className] ?? null;\n    }\n\n    public static function getFunctionDoc(string $functionName): ?string\n    {\n        self::init();\n\n        return self::$functionStubs[$functionName] ?? null;\n    }\n\n    public static function hasMethodStub(string $className, string $methodName): bool\n    {\n        self::init();\n\n        return isset(self::$methodStubs[$className . '::' . $methodName]);\n    }\n\n    public static function hasPropertyStub(string $className, string $propertyName): bool\n    {\n        self::init();\n\n        return isset(self::$propertyStubs[$className . '::$' . $propertyName]);\n    }\n\n    public static function hasClassStub(string $className): bool\n    {\n        self::init();\n\n        return isset(self::$classStubs[$className]);\n    }\n\n    public static function hasFunctionStub(string $functionName): bool\n    {\n        self::init();\n\n        return isset(self::$functionStubs[$functionName]);\n    }\n\n    /**\n     * @param array<int, string> $globs\n     */\n    private static function loadStubFiles(array $globs): void\n    {\n        $projectRoot = Config::getProjectRoot();\n        $parser = StreamWrapper::getParser();\n\n        foreach ($globs as $pattern) {\n            $files = self::resolveStubFiles($pattern, $projectRoot);\n\n            foreach ($files as $file) {\n                $source = file_get_contents($file);\n                if ($source !== false) {\n                    try {\n                        $stmts = $parser->parse($source);\n                        if ($stmts !== null) {\n                            self::extractStubsFromAst($stmts);\n                        }\n                    } catch (Throwable $e) {\n                        // Silently ignore malformed stub files\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Resolves files matching any file extension (.stub, .stub.php, .php, custom) for a glob pattern.\n     *\n     * @return list<string>\n     */\n    private static function resolveStubFiles(string $pattern, string $projectRoot): array\n    {\n        $pattern = str_replace('\\\\', '/', trim($pattern));\n        $isAbsolute = str_starts_with($pattern, '/') || (bool) preg_match('#^[a-zA-Z]:/#', $pattern);\n        $fullPath = $isAbsolute ? $pattern : ($projectRoot . '/' . ltrim($pattern, '/'));\n\n        if (is_file($fullPath)) {\n            return [$fullPath];\n        }\n\n        if (str_contains($pattern, '*')) {\n            $parts = explode('*', $fullPath, 2);\n            $rawPrefix = rtrim($parts[0], '/');\n            $baseDir = is_dir($rawPrefix) ? $rawPrefix : \\dirname($rawPrefix);\n\n            if (! is_dir($baseDir)) {\n                return [];\n            }\n\n            $regex = PathMatcher::compileGlobToRegex($pattern, $projectRoot);\n            $matchedFiles = [];\n\n            $iterator = new RecursiveIteratorIterator(\n                new RecursiveDirectoryIterator($baseDir, FilesystemIterator::SKIP_DOTS)\n            );\n\n            foreach ($iterator as $fileInfo) {\n                if ($fileInfo instanceof SplFileInfo && $fileInfo->isFile()) {\n                    $real = str_replace('\\\\', '/', (string) $fileInfo->getRealPath());\n                    if (preg_match($regex, $real) === 1 || preg_match($regex, str_replace('\\\\', '/', $fileInfo->getPathname())) === 1) {\n                        $matchedFiles[] = $real;\n                    }\n                }\n            }\n\n            return $matchedFiles;\n        }\n\n        if (is_dir($fullPath)) {\n            $matchedFiles = [];\n\n            $iterator = new RecursiveIteratorIterator(\n                new RecursiveDirectoryIterator($fullPath, FilesystemIterator::SKIP_DOTS)\n            );\n            foreach ($iterator as $fileInfo) {\n                if ($fileInfo instanceof SplFileInfo && $fileInfo->isFile()) {\n                    $real = $fileInfo->getRealPath();\n                    if ($real !== false) {\n                        $matchedFiles[] = str_replace('\\\\', '/', $real);\n                    }\n                }\n            }\n\n            return $matchedFiles;\n        }\n\n        return [];\n    }\n\n    /**\n     * @param array<Node\\Stmt> $stmts\n     */\n    private static function extractStubsFromAst(array $stmts, string $namespace = ''): void\n    {\n        foreach ($stmts as $stmt) {\n            if ($stmt instanceof Node\\Stmt\\Namespace_) {\n                $ns = $stmt->name !== null ? $stmt->name->toString() : '';\n                self::extractStubsFromAst($stmt->stmts, $ns);\n            } elseif ($stmt instanceof Node\\Stmt\\Function_) {\n                $funcName = $namespace !== '' ? $namespace . '\\\\' . $stmt->name->toString() : $stmt->name->toString();\n                $doc = $stmt->getDocComment();\n                if ($doc !== null) {\n                    self::$functionStubs[$funcName] = $doc->getText();\n                }\n            } elseif (\n                $stmt instanceof Node\\Stmt\\Class_\n                || $stmt instanceof Node\\Stmt\\Interface_\n                || $stmt instanceof Node\\Stmt\\Trait_\n                || $stmt instanceof Node\\Stmt\\Enum_\n            ) {\n                if ($stmt->name === null) {\n                    continue;\n                }\n\n                $className = $namespace !== '' ? $namespace . '\\\\' . $stmt->name->toString() : $stmt->name->toString();\n\n                $classDoc = $stmt->getDocComment();\n                if ($classDoc !== null) {\n                    self::$classStubs[$className] = $classDoc->getText();\n                }\n\n                foreach ($stmt->stmts as $member) {\n                    if ($member instanceof Node\\Stmt\\ClassMethod) {\n                        $mDoc = $member->getDocComment();\n                        if ($mDoc !== null) {\n                            self::$methodStubs[$className . '::' . $member->name->toString()] = $mDoc->getText();\n                        }\n                    } elseif ($member instanceof Node\\Stmt\\Property) {\n                        $pDoc = $member->getDocComment();\n                        if ($pDoc !== null) {\n                            foreach ($member->props as $prop) {\n                                self::$propertyStubs[$className . '::$' . $prop->name->toString()] = $pDoc->getText();\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}\n","/typephp/src/Internal/Validator/ArrayShapeValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\n\n/**\n * @internal Class for validating array shapes and tuple shapes like array{0: string, 1: int} or array{string, int}.\n */\nfinal class ArrayShapeValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_array($value)) {\n            return ErrorFactory::createError($context . ' must be of type array, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        /** @var ArrayShapeNode $shapeNode */\n        $shapeNode = $node;\n\n        if ($shapeNode->kind === ArrayShapeNode::KIND_LIST && \\count($value) > 0 && ! array_is_list($value)) {\n            return ErrorFactory::createError($context . ' must be a list, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $knownKeys = [];\n        $nextAutoIndex = 0;\n        $matchedKeysCount = 0;\n\n        foreach ($shapeNode->items as $item) {\n            $key = null;\n\n            if ($item->keyName instanceof ConstExprStringNode) {\n                $key = $item->keyName->value;\n            } elseif ($item->keyName instanceof ConstExprIntegerNode) {\n                $key = (int) $item->keyName->value;\n                $nextAutoIndex = max($nextAutoIndex, $key + 1);\n            } elseif ($item->keyName instanceof IdentifierTypeNode) {\n                $key = $item->keyName->name;\n            } elseif ($item->keyName !== null) {\n                $key = (string) $item->keyName;\n            } else {\n                $key = $nextAutoIndex;\n                $nextAutoIndex++;\n            }\n\n            $knownKeys[$key] = true;\n\n            if (! \\array_key_exists($key, $value)) {\n                if (! $item->optional) {\n                    return ErrorFactory::createError($context . \" is missing required key '$key'\");\n                }\n\n                continue;\n            }\n\n            $matchedKeysCount++;\n\n            $err = $registry->validate($value[$key], $item->valueType, '', $isSensitive);\n            if ($err !== null) {\n                return ErrorFactory::createError($context . \"['\" . $key . \"']\" . $err->getMessage());\n            }\n        }\n\n        $valueCount = \\count($value);\n\n        if ($valueCount === $matchedKeysCount) {\n            return null;\n        }\n\n        if ($shapeNode->sealed) {\n            foreach ($value as $k => $_) {\n                if (! isset($knownKeys[$k])) {\n                    return ErrorFactory::createError($context . \" contains unsealed unexpected key '{$k}'\");\n                }\n            }\n        }\n\n        if ($shapeNode->unsealedType !== null) {\n            $unsealedKeyType = $shapeNode->unsealedType->keyType;\n            $unsealedValueType = $shapeNode->unsealedType->valueType;\n\n            foreach ($value as $k => $v) {\n                if (isset($knownKeys[$k])) {\n                    continue;\n                }\n\n                if ($unsealedKeyType !== null) {\n                    $err = $registry->validate($k, $unsealedKeyType, '');\n                    if ($err !== null) {\n                        return ErrorFactory::createError($context . \" extra key '{$k}'\" . $err->getMessage());\n                    }\n                }\n\n                $err = $registry->validate($v, $unsealedValueType, '', $isSensitive);\n                if ($err !== null) {\n                    return ErrorFactory::createError($context . \"['{$k}']\" . $err->getMessage());\n                }\n            }\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Validator/ArrayValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse Generator;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse Traversable;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Util\\Config;\n\n/**\n * Validates array and Traversable collection instances against ArrayTypeNode ASTs (Type[]).\n * Supports both exhaustive O(n) verification and Beartype-style hybrid O(1) sampling.\n *\n * @internal\n */\nfinal class ArrayValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_array($value) && ! ($value instanceof Traversable)) {\n            return ErrorFactory::createError($context . ' must be of type array, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        /** @var ArrayTypeNode $arrayNode */\n        $arrayNode = $node;\n\n        if ($value instanceof Generator) {\n            return null;\n        }\n\n        if (\\is_array($value)) {\n            $count = \\count($value);\n            if ($count === 0) {\n                return null;\n            }\n\n            if ($count > Config::HYBRID_SAMPLE_THRESHOLD && Config::isArrayValidationHybrid()) {\n                return $this->validateArrayHybrid($value, $arrayNode, $context, $registry, $count);\n            }\n\n            foreach ($value as $k => $v) {\n                $err = $registry->validate($v, $arrayNode->type, '', $isSensitive);\n                if ($err !== null) {\n                    $keyStr = \\is_string($k) ? \"'\" . $k . \"'\" : (string) $k;\n\n                    return ErrorFactory::createError($context . '[' . $keyStr . ']' . $err->getMessage());\n                }\n            }\n\n            return null;\n        }\n\n        foreach ($value as $k => $v) {\n            $err = $registry->validate($v, $arrayNode->type, '', $isSensitive);\n            if ($err !== null) {\n                $keyStr = \\is_string($k)\n                    ? \"'\" . $k . \"'\"\n                    : ((\\is_scalar($k) || $k === null) ? (string) $k : get_debug_type($k));\n\n                return ErrorFactory::createError($context . '[' . $keyStr . ']' . $err->getMessage());\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array<mixed> $value\n     */\n    private function validateArrayHybrid(\n        array $value,\n        ArrayTypeNode $arrayNode,\n        string $context,\n        TypeValidatorRegistry $registry,\n        int $count\n    ): ?ErrorMessage {\n        if (array_is_list($value)) {\n            $sampleIndices = [0, $count - 1];\n            $samplesToTake = min(3, $count - 2);\n            for ($i = 0; $i < $samplesToTake; $i++) {\n                $sampleIndices[] = mt_rand(1, $count - 2);\n            }\n\n            foreach ($sampleIndices as $idx) {\n                $err = $registry->validate($value[$idx], $arrayNode->type, '');\n                if ($err !== null) {\n                    return ErrorFactory::createError($context . '[' . $idx . ']' . $err->getMessage());\n                }\n            }\n\n            return null;\n        }\n\n        $keys = array_keys($value);\n        $sampleKeys = [$keys[0], $keys[$count - 1]];\n        $samplesToTake = min(3, $count - 2);\n        for ($i = 0; $i < $samplesToTake; $i++) {\n            $sampleKeys[] = $keys[mt_rand(1, $count - 2)];\n        }\n\n        foreach ($sampleKeys as $k) {\n            $err = $registry->validate($value[$k], $arrayNode->type, '');\n            if ($err !== null) {\n                $keyStr = \\is_string($k) ? \"'\" . $k . \"'\" : (string) $k;\n\n                return ErrorFactory::createError($context . '[' . $keyStr . ']' . $err->getMessage());\n            }\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Validator/ConstValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFalseNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprFloatNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNullNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprTrueNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse ReflectionClass;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\n\n/**\n * @internal Validates literal values, class constants, and wildcard constant patterns (Class::PREFIX_*) against ConstTypeNode ASTs.\n */\nfinal class ConstValidator implements TypeValidatorInterface\n{\n    /**\n     * 2D Cache for wildcard constant values: [$className][$pattern] => array{list: list<mixed>, map: array<string|int, true>}.\n     *\n     * @var array<string, array<string, array{list: list<mixed>, map: array<string|int, true>}>>\n     */\n    private static array $wildcardConstantCache = [];\n\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        /** @var ConstTypeNode $constTypeNode */\n        $constTypeNode = $node;\n        $constExpr = $constTypeNode->constExpr;\n\n        if ($constExpr instanceof ConstExprStringNode) {\n            $expected = $constExpr->value;\n        } elseif ($constExpr instanceof ConstExprTrueNode) {\n            $expected = true;\n        } elseif ($constExpr instanceof ConstExprFalseNode) {\n            $expected = false;\n        } elseif ($constExpr instanceof ConstExprNullNode) {\n            $expected = null;\n        } elseif ($constExpr instanceof ConstExprIntegerNode) {\n            $expected = (int) $constExpr->value;\n        } elseif ($constExpr instanceof ConstExprFloatNode) {\n            $expected = (float) $constExpr->value;\n        } elseif ($constExpr instanceof ConstFetchNode) {\n            $className = $constExpr->className;\n            $pattern = $constExpr->name;\n\n            if (str_contains($pattern, '*')) {\n                $allowed = self::resolveWildcardConstantValues($className, $pattern);\n\n                $isValid = (\\is_int($value) || \\is_string($value))\n                    ? isset($allowed['map'][$value])\n                    : \\in_array($value, $allowed['list'], strict: true);\n\n                if (! $isValid) {\n                    $fqcnPattern = $className !== '' ? \"$className::$pattern\" : $pattern;\n\n                    return ErrorFactory::createError($context . \" must be a valid constant matching $fqcnPattern, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                }\n\n                return null;\n            }\n\n            $fqcnConstant = $className !== ''\n                ? $className . '::' . $pattern\n                : $pattern;\n\n            if (\\defined($fqcnConstant)) {\n                $expected = \\constant($fqcnConstant);\n            } else {\n                $expected = (string) $constExpr;\n            }\n        } else {\n            $expected = (string) $constExpr;\n        }\n\n        if (\\is_float($expected)) {\n            if ((! \\is_float($value) && ! \\is_int($value)) || abs((float) $value - $expected) > 1e-9) {\n                return ErrorFactory::createError($context . ' must be literal ' . (string) $constExpr . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n            }\n\n            return null;\n        }\n\n        if ($value !== $expected) {\n            return ErrorFactory::createError($context . ' must be literal ' . (string) $constExpr . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return null;\n    }\n\n    /**\n     * Resolves and caches all values of class constants matching a wildcard pattern (e.g. PREFIX_*).\n     *\n     * @return array{list: list<mixed>, map: array<string|int, true>}\n     */\n    private static function resolveWildcardConstantValues(string $className, string $pattern): array\n    {\n        if (isset(self::$wildcardConstantCache[$className][$pattern])) {\n            return self::$wildcardConstantCache[$className][$pattern];\n        }\n\n        $list = [];\n        $map = [];\n\n        if ($className !== '' && (class_exists($className, false) || class_exists($className) || interface_exists($className, false) || interface_exists($className))) {\n            /** @var class-string<object> $className */\n            $refClass = new ReflectionClass($className);\n            $regex = '/^' . str_replace('\\*', '.*', preg_quote($pattern, '/')) . '$/i';\n\n            foreach ($refClass->getConstants() as $cName => $cValue) {\n                if (preg_match($regex, $cName) === 1) {\n                    $list[] = $cValue;\n                    if (\\is_int($cValue) || \\is_string($cValue)) {\n                        $map[$cValue] = true;\n                    }\n                }\n            }\n        }\n\n        return self::$wildcardConstantCache[$className][$pattern] = [\n            'list' => $list,\n            'map' => $map,\n        ];\n    }\n}\n","/typephp/src/Internal/Validator/GenericValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\RuntimeTypeChecker;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\nuse TypePHP\\Internal\\Util\\Config;\n\n/**\n * @internal Validates values against generic AST structures (int ranges, class-string<T>, list<T>, array<K,V>, object generics, key-of, value-of, int-mask, int-mask-of).\n */\nfinal class GenericValidator implements TypeValidatorInterface\n{\n    private const BUILTIN_GENERICS = [\n        'int' => true,\n        'integer' => true,\n        'class-string' => true,\n        'list' => true,\n        'non-empty-list' => true,\n        'non-empty-array-list' => true,\n        'array' => true,\n        'non-empty-array' => true,\n        'iterable' => true,\n        'traversable' => true,\n        'generator' => true,\n        'iterator' => true,\n        'key-of' => true,\n        'value-of' => true,\n        'int-mask' => true,\n        'int-mask-of' => true,\n    ];\n\n    /**\n     * @var array<string, mixed>\n     */\n    private static array $constantCache = [];\n\n    /**\n     * @var array<string, array<int, string>>\n     */\n    private static array $enumKeyCache = [];\n\n    /**\n     * @var array<string, array<int, string|int>>\n     */\n    private static array $enumValueCache = [];\n\n    /**\n     * Validates a value against a GenericTypeNode AST.\n     */\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        /** @var GenericTypeNode $genericNode */\n        $genericNode = $node;\n        $baseType = strtolower($genericNode->type->name);\n\n        return match ($baseType) {\n            'int', 'integer' => $this->validateIntRange($value, $genericNode, $context, $isSensitive),\n            'class-string' => $this->validateClassString($value, $genericNode, $context, $isSensitive),\n            'list', 'non-empty-list', 'non-empty-array-list' => $this->validateList($value, $genericNode, $context, $registry, $isSensitive),\n            'array', 'non-empty-array', 'iterable', 'traversable', 'generator', 'iterator' => $this->validateArray($value, $genericNode, $context, $registry, $isSensitive),\n            'key-of' => $this->validateKeyOf($value, $genericNode, $context, $registry, $isSensitive),\n            'value-of' => $this->validateValueOf($value, $genericNode, $context, $registry, $isSensitive),\n            'int-mask' => $this->validateIntMask($value, $genericNode, $context, $isSensitive),\n            'int-mask-of' => $this->validateIntMaskOf($value, $genericNode, $context, $isSensitive),\n            default => $this->validateObjectGeneric($value, $genericNode, $context, $isSensitive),\n        };\n    }\n\n    private function resolveConstantValue(string $fqcn, string $constName): mixed\n    {\n        $cacheKey = $fqcn !== '' ? \"$fqcn::$constName\" : $constName;\n\n        if (! \\array_key_exists($cacheKey, self::$constantCache)) {\n            $constValue = false;\n            if ($fqcn !== '') {\n                if (class_exists($fqcn) || interface_exists($fqcn)) {\n                    $refClass = new \\ReflectionClass($fqcn);\n                    if ($refClass->hasConstant($constName)) {\n                        $constValue = $refClass->getConstant($constName);\n                    }\n                }\n            } else {\n                if (\\defined($constName)) {\n                    $constValue = \\constant($constName);\n                }\n            }\n            self::$constantCache[$cacheKey] = $constValue;\n        }\n\n        return self::$constantCache[$cacheKey];\n    }\n\n    private function validateKeyOf(mixed $value, GenericTypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        $targetType = $node->genericTypes[0] ?? null;\n\n        if ($targetType instanceof GenericTypeNode && strtolower($targetType->type->name) === 'value-of') {\n            $innerTarget = $targetType->genericTypes[0] ?? null;\n            if ($innerTarget instanceof ArrayShapeNode) {\n                $validKeys = [];\n                foreach ($innerTarget->items as $item) {\n                    if ($item->valueType instanceof ArrayShapeNode) {\n                        foreach ($item->valueType->items as $subItem) {\n                            $subKey = self::extractKeyFromItem($subItem);\n                            if ($subKey !== null) {\n                                $validKeys[] = $subKey;\n                            }\n                        }\n                    }\n                }\n                if (! \\in_array($value, $validKeys, strict: true)) {\n                    return ErrorFactory::createError($context . ' must be a key of the specified array shape, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                }\n\n                return null;\n            }\n        }\n\n        if ($targetType instanceof ConstTypeNode && $targetType->constExpr instanceof ConstFetchNode) {\n            $constExpr = $targetType->constExpr;\n            $fqcn = $constExpr->className;\n            $constName = $constExpr->name;\n            $cacheKey = $fqcn !== '' ? \"$fqcn::$constName\" : $constName;\n\n            $constValue = $this->resolveConstantValue($fqcn, $constName);\n\n            if (\\is_array($constValue)) {\n                if ((! \\is_int($value) && ! \\is_string($value)) || ! \\array_key_exists($value, $constValue)) {\n                    return ErrorFactory::createError($context . \" must be a key of $cacheKey, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                }\n\n                return null;\n            }\n        } elseif ($targetType instanceof IdentifierTypeNode) {\n            $enumClass = $targetType->name;\n            if (ClassNameValidator::isValid($enumClass) && enum_exists($enumClass)) {\n                if (! isset(self::$enumKeyCache[$enumClass])) {\n                    self::$enumKeyCache[$enumClass] = array_map(fn ($case) => $case->name, $enumClass::cases());\n                }\n\n                if (! \\in_array($value, self::$enumKeyCache[$enumClass], strict: true)) {\n                    return ErrorFactory::createError($context . \" must be a key of enum $enumClass, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                }\n\n                return null;\n            }\n        } elseif ($targetType instanceof ArrayShapeNode) {\n            $validKeys = [];\n            $nextAutoIndex = 0;\n\n            foreach ($targetType->items as $item) {\n                if ($item->keyName instanceof ConstExprStringNode) {\n                    $validKeys[] = $item->keyName->value;\n                } elseif ($item->keyName instanceof IdentifierTypeNode) {\n                    $validKeys[] = $item->keyName->name;\n                } elseif ($item->keyName instanceof ConstExprIntegerNode) {\n                    $key = (int) $item->keyName->value;\n                    $validKeys[] = $key;\n                    $nextAutoIndex = max($nextAutoIndex, $key + 1);\n                } elseif ($item->keyName !== null) {\n                    $validKeys[] = (string) $item->keyName;\n                } else {\n                    $validKeys[] = $nextAutoIndex;\n                    $nextAutoIndex++;\n                }\n            }\n\n            if (! \\in_array($value, $validKeys, strict: true)) {\n                return ErrorFactory::createError($context . ' must be a key of the specified array shape, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n            }\n\n            return null;\n        }\n\n        return null;\n    }\n\n    private static function extractKeyFromItem(ArrayShapeItemNode $item): string|int|null\n    {\n        $keyName = $item->keyName;\n\n        if ($keyName instanceof ConstExprStringNode) {\n            return $keyName->value;\n        }\n        if ($keyName instanceof ConstExprIntegerNode) {\n            return (int) $keyName->value;\n        }\n        if ($keyName instanceof IdentifierTypeNode) {\n            return $keyName->name;\n        }\n        if ($keyName instanceof ConstFetchNode) {\n            return (string) $keyName;\n        }\n\n        return null;\n    }\n\n    private function validateValueOf(mixed $value, GenericTypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        $targetType = $node->genericTypes[0] ?? null;\n\n        if ($targetType instanceof ConstTypeNode && $targetType->constExpr instanceof ConstFetchNode) {\n            $constExpr = $targetType->constExpr;\n            $fqcn = $constExpr->className;\n            $constName = $constExpr->name;\n            $cacheKey = $fqcn !== '' ? \"$fqcn::$constName\" : $constName;\n\n            $constValue = $this->resolveConstantValue($fqcn, $constName);\n\n            if (\\is_array($constValue)) {\n                if (! \\in_array($value, $constValue, strict: true)) {\n                    return ErrorFactory::createError($context . \" must be a value of $cacheKey, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                }\n\n                return null;\n            }\n        } elseif ($targetType instanceof IdentifierTypeNode) {\n            $enumClass = $targetType->name;\n            if (ClassNameValidator::isValid($enumClass) && enum_exists($enumClass)) {\n                if (is_subclass_of($enumClass, \\BackedEnum::class)) {\n                    if (! isset(self::$enumValueCache[$enumClass])) {\n                        self::$enumValueCache[$enumClass] = array_map(fn ($case) => $case->value, $enumClass::cases());\n                    }\n\n                    if (! \\in_array($value, self::$enumValueCache[$enumClass], strict: true)) {\n                        return ErrorFactory::createError($context . \" must be a value of enum $enumClass, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n                    }\n\n                    return null;\n                }\n\n                return ErrorFactory::createError($context . \" must be a value of enum $enumClass, \" . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n            }\n        } elseif ($targetType instanceof ArrayShapeNode) {\n            foreach ($targetType->items as $item) {\n                if ($registry->validate($value, $item->valueType, '', $isSensitive) === null) {\n                    return null;\n                }\n            }\n\n            return ErrorFactory::createError($context . ' must be a value of the specified array shape, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return null;\n    }\n\n    private function validateIntMask(mixed $value, GenericTypeNode $node, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_int($value)) {\n            return ErrorFactory::createError($context . ' must be of type int (bitmask), ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $allowedMask = 0;\n\n        foreach ($node->genericTypes as $typeNode) {\n            if ($typeNode instanceof ConstTypeNode) {\n                $expr = $typeNode->constExpr;\n                if ($expr instanceof ConstExprIntegerNode) {\n                    $allowedMask |= (int) $expr->value;\n                } elseif ($expr instanceof ConstFetchNode) {\n                    $constVal = $this->resolveConstantValue($expr->className, $expr->name);\n                    if (\\is_int($constVal)) {\n                        $allowedMask |= $constVal;\n                    }\n                }\n            }\n        }\n\n        if (($value & ~$allowedMask) !== 0) {\n            return ErrorFactory::createError($context . ' must be a valid bitmask combination of the allowed flags, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return null;\n    }\n\n    private function validateIntMaskOf(mixed $value, GenericTypeNode $node, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_int($value)) {\n            return ErrorFactory::createError($context . ' must be of type int (bitmask), ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $targetType = $node->genericTypes[0] ?? null;\n        $allowedMask = 0;\n        $foundFlags = false;\n\n        if ($targetType instanceof ConstTypeNode && $targetType->constExpr instanceof ConstFetchNode) {\n            $constExpr = $targetType->constExpr;\n            $fqcn = $constExpr->className;\n            $pattern = $constExpr->name;\n\n            if ($fqcn !== '' && (class_exists($fqcn) || interface_exists($fqcn))) {\n                $refClass = new \\ReflectionClass($fqcn);\n\n                if (str_contains($pattern, '*')) {\n                    $regex = '/^' . str_replace('\\*', '.*', preg_quote($pattern, '/')) . '$/i';\n                    foreach ($refClass->getConstants() as $cName => $cValue) {\n                        if (\\is_int($cValue) && preg_match($regex, $cName) === 1) {\n                            $allowedMask |= $cValue;\n                            $foundFlags = true;\n                        }\n                    }\n                } else {\n                    $cValue = $this->resolveConstantValue($fqcn, $pattern);\n                    if (\\is_int($cValue)) {\n                        $allowedMask |= $cValue;\n                        $foundFlags = true;\n                    } elseif (\\is_array($cValue)) {\n                        foreach ($cValue as $item) {\n                            if (\\is_int($item)) {\n                                $allowedMask |= $item;\n                                $foundFlags = true;\n                            }\n                        }\n                    }\n                }\n            }\n        }\n\n        if ($foundFlags && ($value & ~$allowedMask) !== 0) {\n            return ErrorFactory::createError($context . ' must be a valid bitmask combination of the allowed flags, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return null;\n    }\n\n    private function validateIntRange(mixed $value, GenericTypeNode $node, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_int($value)) {\n            return ErrorFactory::createError($context . ' must be of type int, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $minNode = $node->genericTypes[0] ?? null;\n        $maxNode = $node->genericTypes[1] ?? null;\n\n        if ($minNode !== null) {\n            $minStr = strtolower(trim((string) $minNode));\n            if ($minStr !== 'min' && $minStr !== '*') {\n                $minVal = (int) $minStr;\n                if ($value < $minVal) {\n                    $valDisplay = $isSensitive ? 'int given' : \"$value given\";\n\n                    return ErrorFactory::createError($context . \" must be >= $minVal, $valDisplay\");\n                }\n            }\n        }\n\n        if ($maxNode !== null) {\n            $maxStr = strtolower(trim((string) $maxNode));\n            if ($maxStr !== 'max' && $maxStr !== '*') {\n                $maxVal = (int) $maxStr;\n                if ($value > $maxVal) {\n                    $valDisplay = $isSensitive ? 'int given' : \"$value given\";\n\n                    return ErrorFactory::createError($context . \" must be <= $maxVal, $valDisplay\");\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private function validateClassString(mixed $value, GenericTypeNode $node, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! \\is_string($value) || ! ClassNameValidator::isValidClassString($value)) {\n            return ErrorFactory::createError($context . ' must be a valid class-string, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $targetClassNode = $node->genericTypes[0] ?? null;\n        if ($targetClassNode === null) {\n            return null;\n        }\n\n        return $this->validateClassStringBound($value, $targetClassNode, $context, $isSensitive);\n    }\n\n    private function validateClassStringBound(string $value, TypeNode $targetNode, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if ($targetNode instanceof IdentifierTypeNode) {\n            $targetName = $targetNode->name;\n            $lower = strtolower($targetName);\n            if ($lower === 'object' || $lower === 'mixed') {\n                return null;\n            }\n\n            if (class_exists($targetName) || interface_exists($targetName) || trait_exists($targetName) || enum_exists($targetName)) {\n                if (! is_a($value, $targetName, allow_string: true)) {\n                    $valDisplay = $isSensitive ? 'string given' : \"'$value' given\";\n\n                    return ErrorFactory::createError($context . ' must be a class-string of ' . $targetName . \", $valDisplay\");\n                }\n            }\n\n            return null;\n        }\n\n        if ($targetNode instanceof UnionTypeNode) {\n            foreach ($targetNode->types as $unionType) {\n                if ($this->validateClassStringBound($value, $unionType, $context, $isSensitive) === null) {\n                    return null;\n                }\n            }\n\n            $valDisplay = $isSensitive ? 'string given' : \"'$value' given\";\n\n            return ErrorFactory::createError($context . ' must be a class-string of ' . (string) $targetNode . \", $valDisplay\");\n        }\n\n        if ($targetNode instanceof IntersectionTypeNode) {\n            foreach ($targetNode->types as $intersectionType) {\n                $err = $this->validateClassStringBound($value, $intersectionType, $context, $isSensitive);\n                if ($err !== null) {\n                    return $err;\n                }\n            }\n\n            return null;\n        }\n\n        return null;\n    }\n\n    private function validateList(mixed $value, GenericTypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        $baseType = strtolower($node->type->name);\n\n        if (! \\is_array($value) || (\\count($value) > 0 && ! array_is_list($value))) {\n            return ErrorFactory::createError($context . ' must be a list, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        $count = \\count($value);\n\n        if (str_contains($baseType, 'non-empty') && $count === 0) {\n            return ErrorFactory::createError($context . ' must be a non-empty list, empty array given');\n        }\n\n        $valueTypeNode = $node->genericTypes[0] ?? null;\n        if ($valueTypeNode === null || $count === 0) {\n            return null;\n        }\n\n        if ($valueTypeNode instanceof IdentifierTypeNode && \\in_array(strtolower($valueTypeNode->name), ['mixed', 't', 'tvalue', 'v', 'value', 'telement'], true)) {\n            return null;\n        }\n\n        $isComplexObjectGeneric = ($valueTypeNode instanceof GenericTypeNode && ! isset(self::BUILTIN_GENERICS[strtolower($valueTypeNode->type->name)]));\n\n        if ($count > Config::HYBRID_SAMPLE_THRESHOLD && Config::isArrayValidationHybrid()) {\n            $sampleIndices = [0, $count - 1];\n            $samplesToTake = min(3, $count - 2);\n            for ($i = 0; $i < $samplesToTake; $i++) {\n                $sampleIndices[] = mt_rand(1, $count - 2);\n            }\n\n            foreach ($sampleIndices as $k) {\n                $v = $value[$k];\n                $err = $isComplexObjectGeneric\n                    ? $this->validateObjectGeneric($v, $valueTypeNode, '', $isSensitive)\n                    : $registry->validate($v, $valueTypeNode, '', $isSensitive);\n\n                if ($err !== null) {\n                    return ErrorFactory::createError($context . '[' . $k . ']' . $err->getMessage());\n                }\n            }\n\n            return null;\n        }\n\n        foreach ($value as $k => $v) {\n            $err = $isComplexObjectGeneric\n                ? $this->validateObjectGeneric($v, $valueTypeNode, '', $isSensitive)\n                : $registry->validate($v, $valueTypeNode, '', $isSensitive);\n\n            if ($err !== null) {\n                return ErrorFactory::createError($context . '[' . $k . ']' . $err->getMessage());\n            }\n        }\n\n        return null;\n    }\n\n    private function validateArray(mixed $value, GenericTypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        $baseType = strtolower($node->type->name);\n\n        if (! \\is_array($value) && ! ($value instanceof \\Traversable)) {\n            return ErrorFactory::createError($context . ' must be of type ' . $node->type->name . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        if (! \\is_array($value)) {\n            return null;\n        }\n\n        $count = \\count($value);\n\n        if (str_contains($baseType, 'non-empty') && $count === 0) {\n            return ErrorFactory::createError($context . ' must be a non-empty array, empty array given');\n        }\n\n        if ($count === 0) {\n            return null;\n        }\n\n        $typesCount = \\count($node->genericTypes);\n        if ($typesCount === 1) {\n            $valTypeNode = $node->genericTypes[0];\n\n            if ($valTypeNode instanceof IdentifierTypeNode && \\in_array(strtolower($valTypeNode->name), ['mixed', 't', 'tvalue', 'v', 'value', 'telement'], true)) {\n                return null;\n            }\n\n            $isComplexObjectGeneric = ($valTypeNode instanceof GenericTypeNode && ! isset(self::BUILTIN_GENERICS[strtolower($valTypeNode->type->name)]));\n            if ($count > Config::HYBRID_SAMPLE_THRESHOLD && Config::isArrayValidationHybrid()) {\n                $keys = array_keys($value);\n                $sampleKeys = [$keys[0], $keys[$count - 1]];\n                $samplesToTake = min(3, $count - 2);\n                for ($i = 0; $i < $samplesToTake; $i++) {\n                    $sampleKeys[] = $keys[mt_rand(1, $count - 2)];\n                }\n\n                foreach ($sampleKeys as $k) {\n                    $v = $value[$k];\n                    $err = $isComplexObjectGeneric\n                        ? $this->validateObjectGeneric($v, $valTypeNode, '', $isSensitive)\n                        : $registry->validate($v, $valTypeNode, '', $isSensitive);\n\n                    if ($err !== null) {\n                        return ErrorFactory::createError($context . '[' . $k . ']' . $err->getMessage());\n                    }\n                }\n\n                return null;\n            }\n\n            foreach ($value as $k => $v) {\n                $err = $isComplexObjectGeneric\n                    ? $this->validateObjectGeneric($v, $valTypeNode, '', $isSensitive)\n                    : $registry->validate($v, $valTypeNode, '', $isSensitive);\n\n                if ($err !== null) {\n                    return ErrorFactory::createError($context . '[' . $k . ']' . $err->getMessage());\n                }\n            }\n        } elseif ($typesCount >= 2) {\n            $keyTypeNode = $node->genericTypes[0];\n            $valTypeNode = $node->genericTypes[1];\n\n            $keyIsArrayKey = ($keyTypeNode instanceof IdentifierTypeNode) && \\in_array(strtolower($keyTypeNode->name), ['array-key', 'mixed', 'tkey', 'key', 'k'], true);\n            $valIsMixed = ($valTypeNode instanceof IdentifierTypeNode) && \\in_array(strtolower($valTypeNode->name), ['mixed', 'tvalue', 'v', 'value', 't'], true);\n\n            if ($keyIsArrayKey && $valIsMixed) {\n                return null;\n            }\n\n            $isComplexObjectGeneric = ($valTypeNode instanceof GenericTypeNode && ! isset(self::BUILTIN_GENERICS[strtolower($valTypeNode->type->name)]));\n\n            if ($count > Config::HYBRID_SAMPLE_THRESHOLD && Config::isArrayValidationHybrid()) {\n                $keys = array_keys($value);\n                $sampleKeys = [$keys[0], $keys[$count - 1]];\n                $samplesToTake = min(3, $count - 2);\n                for ($i = 0; $i < $samplesToTake; $i++) {\n                    $sampleKeys[] = $keys[mt_rand(1, $count - 2)];\n                }\n\n                foreach ($sampleKeys as $k) {\n                    if (! $keyIsArrayKey) {\n                        $err = $registry->validate($k, $keyTypeNode, '');\n                        if ($err !== null) {\n                            return ErrorFactory::createError($context . ' key' . $err->getMessage());\n                        }\n                    }\n\n                    if (! $valIsMixed) {\n                        $v = $value[$k];\n                        $err = $isComplexObjectGeneric\n                            ? $this->validateObjectGeneric($v, $valTypeNode, '', $isSensitive)\n                            : $registry->validate($v, $valTypeNode, '', $isSensitive);\n\n                        if ($err !== null) {\n                            return ErrorFactory::createError($context . \"['\" . $k . \"']\" . $err->getMessage());\n                        }\n                    }\n                }\n\n                return null;\n            }\n\n            foreach ($value as $k => $v) {\n                if (! $keyIsArrayKey) {\n                    $err = $registry->validate($k, $keyTypeNode, '');\n                    if ($err !== null) {\n                        return ErrorFactory::createError($context . ' key' . $err->getMessage());\n                    }\n                }\n\n                if (! $valIsMixed) {\n                    $err = $isComplexObjectGeneric\n                        ? $this->validateObjectGeneric($v, $valTypeNode, '', $isSensitive)\n                        : $registry->validate($v, $valTypeNode, '', $isSensitive);\n\n                    if ($err !== null) {\n                        return ErrorFactory::createError($context . \"['\" . $k . \"']\" . $err->getMessage());\n                    }\n                }\n            }\n        }\n\n        return null;\n    }\n\n    private function validateObjectGeneric(mixed $value, GenericTypeNode $node, string $context, bool $isSensitive = false): ?ErrorMessage\n    {\n        if (! ClassNameValidator::isValid($node->type->name)) {\n            return null;\n        }\n\n        if (! \\is_object($value)) {\n            return ErrorFactory::createError($context . ' must be an object of type ' . $node->type->name . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        if (! is_a($value, $node->type->name)) {\n            return ErrorFactory::createError($context . ' must be an instance of ' . $node->type->name . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return RuntimeTypeChecker::bindInstanceFromNode($value, $node, $context);\n    }\n}\n","/typephp/src/Internal/Validator/IdentifierValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\nuse TypePHP\\Internal\\Wrapper\\CallableWrapper;\n\n/**\n * @internal Class for validating basic scalar identifier types like int, string, bool, array, list, object, callable, resource, null, true, false, mixed, scalar, void.\n */\nfinal class IdentifierValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        /** @var IdentifierTypeNode $identifierNode */\n        $identifierNode = $node;\n        $name = $identifierNode->name;\n        $lower = strtolower($name);\n\n        $ok = match ($lower) {\n            'int', 'integer' => \\is_int($value),\n            'string' => \\is_string($value),\n            'float', 'double' => \\is_float($value) || \\is_int($value),\n            'bool', 'boolean' => \\is_bool($value),\n            'array' => \\is_array($value),\n            'list' => \\is_array($value) && (\\count($value) === 0 || array_is_list($value)),\n            'object', 'self', 'static', 'parent', '$this' => \\is_object($value),\n            'callable', 'pure-callable' => CallableWrapper::isCallable($value),\n            'iterable' => is_iterable($value),\n            'resource' => \\is_resource($value),\n            'null' => $value === null,\n            'true' => $value === true,\n            'false' => $value === false,\n            'mixed' => true,\n            'scalar' => \\is_scalar($value),\n            'void' => $value === null,\n            'never', 'never-return', 'never-returns', 'no-return' => false,\n            'positive-int' => \\is_int($value) && $value > 0,\n            'negative-int' => \\is_int($value) && $value < 0,\n            'non-positive-int' => \\is_int($value) && $value <= 0,\n            'non-negative-int' => \\is_int($value) && $value >= 0,\n            'non-zero-int' => \\is_int($value) && $value !== 0,\n            'unsigned-int' => \\is_int($value) && $value >= 0,\n            'positive-float' => (\\is_float($value) || \\is_int($value)) && $value > 0,\n            'negative-float' => (\\is_float($value) || \\is_int($value)) && $value < 0,\n            'non-positive-float' => (\\is_float($value) || \\is_int($value)) && $value <= 0,\n            'non-negative-float' => (\\is_float($value) || \\is_int($value)) && $value >= 0,\n            'non-zero-float' => (\\is_float($value) || \\is_int($value)) && $value !== 0 && $value !== 0.0,\n            'class-string' => \\is_string($value) && ClassNameValidator::isValidClassString($value),\n            'interface-string' => \\is_string($value) && interface_exists($value),\n            'trait-string' => \\is_string($value) && trait_exists($value),\n            'enum-string' => \\is_string($value) && enum_exists($value),\n            'callable-string' => \\is_string($value) && CallableWrapper::isCallable($value),\n            'numeric-string' => \\is_string($value) && is_numeric($value),\n            'non-empty-string' => \\is_string($value) && $value !== '',\n            'lowercase-string' => \\is_string($value) && strtolower($value) === $value,\n            'non-empty-lowercase-string' => \\is_string($value) && $value !== '' && strtolower($value) === $value,\n            'uppercase-string' => \\is_string($value) && strtoupper($value) === $value,\n            'non-empty-uppercase-string' => \\is_string($value) && $value !== '' && strtoupper($value) === $value,\n            'array-key' => \\is_int($value) || \\is_string($value),\n            'literal-string' => \\is_string($value),\n            'truthy-string', 'non-falsy-string' => \\is_string($value) && (bool) $value === true,\n            'non-empty-array' => \\is_array($value) && \\count($value) > 0,\n            'non-empty-list' => \\is_array($value) && \\count($value) > 0 && array_is_list($value),\n            'number', 'numeric' => \\is_int($value) || \\is_float($value) || (\\is_string($value) && is_numeric($value)),\n            'truthy' => (bool) $value === true,\n            'falsy', 'falsey' => (bool) $value === false,\n            'open-resource' => \\is_resource($value),\n            'closed-resource' => ! \\is_resource($value) && get_debug_type($value) === 'resource (closed)',\n            default => $this->validateClassOrIgnore($value, $name),\n        };\n\n        if (! $ok) {\n            return ErrorFactory::createError($context . ' must be of type ' . $identifierNode->name . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        return null;\n    }\n\n    private function validateClassOrIgnore(mixed $value, string $name): bool\n    {\n        if (! ClassNameValidator::isValid($name)) {\n            return true;\n        }\n\n        return \\is_object($value) && is_a($value, $name);\n    }\n}\n","/typephp/src/Internal/Validator/IntersectionValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\n\nfinal class IntersectionValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        /** @var IntersectionTypeNode $intersectionNode */\n        $intersectionNode = $node;\n\n        $types = $intersectionNode->types;\n\n        if (\\is_array($value)) {\n            $types = self::mergeArrayShapesInTypes($types);\n        }\n\n        if (\\is_object($value)) {\n            $types = self::mergeObjectShapesInTypes($types);\n        }\n\n        foreach ($types as $type) {\n            $err = $registry->validate($value, $type, $context, $isSensitive);\n            if ($err !== null) {\n                $msg = $err->getMessage();\n\n                if (\n                    str_starts_with($msg, $context . '[') ||\n                    str_starts_with($msg, $context . '->') ||\n                    str_starts_with($msg, $context . ' is missing required') ||\n                    str_starts_with($msg, $context . ' contains unsealed') ||\n                    str_starts_with($msg, $context . ' property') ||\n                    str_starts_with($msg, $context . ' key')\n                ) {\n                    return $err;\n                }\n\n                return ErrorFactory::createError(\n                    $context . ' must be of type ' . $intersectionNode . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given'\n                );\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * @param array<TypeNode> $types\n     *\n     * @return array<TypeNode>\n     */\n    private static function mergeArrayShapesInTypes(array $types): array\n    {\n        /** @var list<ArrayShapeNode> $shapes */\n        $shapes = [];\n\n        foreach ($types as $type) {\n            if ($type instanceof ArrayShapeNode) {\n                $shapes[] = $type;\n            }\n        }\n\n        if (\\count($shapes) < 2) {\n            return $types;\n        }\n\n        $mergedShape = self::mergeArrayShapes($shapes);\n\n        $newTypes = [];\n        $mergedInserted = false;\n\n        foreach ($types as $type) {\n            if ($type instanceof ArrayShapeNode) {\n                if (! $mergedInserted) {\n                    $newTypes[] = $mergedShape;\n                    $mergedInserted = true;\n                }\n            } else {\n                $newTypes[] = $type;\n            }\n        }\n\n        return $newTypes;\n    }\n\n    /**\n     * @param list<ArrayShapeNode> $shapes\n     */\n    private static function mergeArrayShapes(array $shapes): ArrayShapeNode\n    {\n        /** @var array<string|int, array{keyName: ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null, optional: bool, valueTypes: list<TypeNode>}> $itemsByKey */\n        $itemsByKey = [];\n        $isSealed = true;\n        $unsealedType = null;\n        $kind = ArrayShapeNode::KIND_ARRAY;\n\n        foreach ($shapes as $shape) {\n            if (! $shape->sealed) {\n                $isSealed = false;\n                if ($shape->unsealedType !== null) {\n                    $unsealedType = $shape->unsealedType;\n                }\n            }\n\n            if ($shape->kind === ArrayShapeNode::KIND_LIST) {\n                $kind = ArrayShapeNode::KIND_LIST;\n            }\n\n            foreach ($shape->items as $item) {\n                $key = self::extractItemKey($item->keyName);\n                if ($key === null) {\n                    $key = \\count($itemsByKey);\n                }\n\n                if (! isset($itemsByKey[$key])) {\n                    $itemsByKey[$key] = [\n                        'keyName' => $item->keyName,\n                        'optional' => $item->optional,\n                        'valueTypes' => [$item->valueType],\n                    ];\n                } else {\n                    $itemsByKey[$key]['optional'] = $itemsByKey[$key]['optional'] && $item->optional;\n                    $itemsByKey[$key]['valueTypes'][] = $item->valueType;\n                }\n            }\n        }\n\n        $mergedItems = [];\n        foreach ($itemsByKey as $info) {\n            $valueType = \\count($info['valueTypes']) === 1\n                ? $info['valueTypes'][0]\n                : new IntersectionTypeNode($info['valueTypes']);\n\n            $mergedItems[] = new ArrayShapeItemNode(\n                $info['keyName'],\n                $info['optional'],\n                $valueType\n            );\n        }\n\n        if ($isSealed) {\n            return ArrayShapeNode::createSealed($mergedItems, $kind);\n        }\n\n        return ArrayShapeNode::createUnsealed($mergedItems, $unsealedType, $kind);\n    }\n\n    /**\n     * @param array<TypeNode> $types\n     *\n     * @return array<TypeNode>\n     */\n    private static function mergeObjectShapesInTypes(array $types): array\n    {\n        /** @var list<ObjectShapeNode> $shapes */\n        $shapes = [];\n\n        foreach ($types as $type) {\n            if ($type instanceof ObjectShapeNode) {\n                $shapes[] = $type;\n            }\n        }\n\n        if (\\count($shapes) < 2) {\n            return $types;\n        }\n\n        $mergedShape = self::mergeObjectShapes($shapes);\n\n        $newTypes = [];\n        $mergedInserted = false;\n\n        foreach ($types as $type) {\n            if ($type instanceof ObjectShapeNode) {\n                if (! $mergedInserted) {\n                    $newTypes[] = $mergedShape;\n                    $mergedInserted = true;\n                }\n            } else {\n                $newTypes[] = $type;\n            }\n        }\n\n        return $newTypes;\n    }\n\n    /**\n     * @param list<ObjectShapeNode> $shapes\n     */\n    private static function mergeObjectShapes(array $shapes): ObjectShapeNode\n    {\n        /** @var array<string, array{keyName: ConstExprStringNode|IdentifierTypeNode, optional: bool, valueTypes: list<TypeNode>}> $itemsByKey */\n        $itemsByKey = [];\n\n        foreach ($shapes as $shape) {\n            foreach ($shape->items as $item) {\n                $prop = (string) $item->keyName;\n\n                if (! isset($itemsByKey[$prop])) {\n                    $itemsByKey[$prop] = [\n                        'keyName' => $item->keyName,\n                        'optional' => $item->optional,\n                        'valueTypes' => [$item->valueType],\n                    ];\n                } else {\n                    $itemsByKey[$prop]['optional'] = $itemsByKey[$prop]['optional'] && $item->optional;\n                    $itemsByKey[$prop]['valueTypes'][] = $item->valueType;\n                }\n            }\n        }\n\n        $mergedItems = [];\n        foreach ($itemsByKey as $info) {\n            $valueType = \\count($info['valueTypes']) === 1\n                ? $info['valueTypes'][0]\n                : new IntersectionTypeNode($info['valueTypes']);\n\n            $mergedItems[] = new ObjectShapeItemNode(\n                $info['keyName'],\n                $info['optional'],\n                $valueType\n            );\n        }\n\n        return new ObjectShapeNode($mergedItems);\n    }\n\n    private static function extractItemKey(ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null $keyName): string|int|null\n    {\n        if ($keyName instanceof ConstExprStringNode) {\n            return $keyName->value;\n        }\n        if ($keyName instanceof ConstExprIntegerNode) {\n            return (int) $keyName->value;\n        }\n        if ($keyName instanceof IdentifierTypeNode) {\n            return $keyName->name;\n        }\n        if ($keyName instanceof ConstFetchNode) {\n            return (string) $keyName;\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Validator/NullableValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\n\n/**\n * @internal Class for validating nullable types like ?int.\n */\nfinal class NullableValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        if ($value === null) {\n            return null;\n        }\n\n        /** @var NullableTypeNode $node */\n        return $registry->validate($value, $node->type, $context, $isSensitive);\n    }\n}\n","/typephp/src/Internal/Validator/ObjectShapeValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse ReflectionClass;\nuse ReflectionProperty;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\n\n/**\n * @internal Validates stdClass dynamic properties and custom class instances against PHPDoc object shape structures.\n */\nfinal class ObjectShapeValidator implements TypeValidatorInterface\n{\n    /**\n     * Cache for ReflectionClass instances per class name.\n     *\n     * @var array<class-string<object>, ReflectionClass<object>>\n     */\n    private static array $refClassCache = [];\n\n    /**\n     * Cache for ReflectionProperty instances per class name and property name.\n     * Stored as false if the property is not declared on the class (dynamic or magic).\n     *\n     * @var array<class-string<object>, array<string, ReflectionProperty|false>>\n     */\n    private static array $propertyCache = [];\n\n    public function validate(\n        mixed $value,\n        TypeNode $node,\n        string $context,\n        TypeValidatorRegistry $registry,\n        bool $isSensitive = false\n    ): ?ErrorMessage {\n        if (! \\is_object($value)) {\n            return ErrorFactory::createError($context . ' must be of type object, ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        /** @var ObjectShapeNode $shapeNode */\n        $shapeNode = $node;\n\n        if ($value instanceof \\stdClass) {\n            foreach ($shapeNode->items as $item) {\n                $propName = $item->keyName instanceof IdentifierTypeNode\n                    ? $item->keyName->name\n                    : (string) $item->keyName;\n\n                if (! isset($value->$propName) && ! property_exists($value, $propName)) {\n                    if (! $item->optional) {\n                        return ErrorFactory::createError($context . \" is missing required property '$propName'\");\n                    }\n\n                    continue;\n                }\n\n                $propValue = $value->$propName;\n\n                $err = $registry->validate($propValue, $item->valueType, '', $isSensitive);\n                if ($err !== null) {\n                    return ErrorFactory::createError($context . \"->{$propName}\" . $err->getMessage());\n                }\n            }\n\n            return null;\n        }\n\n        $className = $value::class;\n\n        foreach ($shapeNode->items as $item) {\n            $propName = $item->keyName instanceof IdentifierTypeNode\n                ? $item->keyName->name\n                : (string) $item->keyName;\n\n            if (! isset(self::$propertyCache[$className][$propName]) && ! \\array_key_exists($propName, self::$propertyCache[$className] ?? [])) {\n                $refClass = self::$refClassCache[$className] ??= new ReflectionClass($className);\n                self::$propertyCache[$className][$propName] = $refClass->hasProperty($propName)\n                    ? $refClass->getProperty($propName)\n                    : false;\n            }\n\n            $refProp = self::$propertyCache[$className][$propName];\n\n            if ($refProp instanceof ReflectionProperty) {\n                if (! $refProp->isInitialized($value)) {\n                    if (! $item->optional) {\n                        return ErrorFactory::createError($context . \" property '$propName' is uninitialized\");\n                    }\n\n                    continue;\n                }\n\n                $propValue = $refProp->getValue($value);\n            } else {\n                // @phpstan-ignore property.dynamicName\n                if (! isset($value->$propName) && ! property_exists($value, $propName)) {\n                    if (! $item->optional) {\n                        return ErrorFactory::createError($context . \" is missing required property '$propName'\");\n                    }\n\n                    continue;\n                }\n\n                // @phpstan-ignore property.dynamicName\n                $propValue = $value->$propName;\n            }\n\n            $err = $registry->validate($propValue, $item->valueType, '', $isSensitive);\n            if ($err !== null) {\n                return ErrorFactory::createError($context . \"->{$propName}\" . $err->getMessage());\n            }\n        }\n\n        return null;\n    }\n}\n","/typephp/src/Internal/Validator/TypeValidatorInterface.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\n\n/**\n * Strategy interface for validating values against specific PHPDoc AST TypeNodes.\n */\ninterface TypeValidatorInterface\n{\n    /**\n     * Validates a value against an AST TypeNode and returns an ErrorMessage on failure or null on success.\n     */\n    public function validate(\n        mixed $value,\n        TypeNode $node,\n        string $context,\n        TypeValidatorRegistry $registry,\n        bool $isSensitive = false\n    ): ?ErrorMessage;\n}\n","/typephp/src/Internal/Validator/TypeValidatorRegistry.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\n\n/**\n * Registry mapping AST TypeNodes to their corresponding validator strategy implementations.\n */\nfinal class TypeValidatorRegistry\n{\n    private IdentifierValidator $identifierValidator;\n\n    private GenericValidator $genericValidator;\n\n    private UnionValidator $unionValidator;\n\n    private IntersectionValidator $intersectionValidator;\n\n    private NullableValidator $nullableValidator;\n\n    private ArrayValidator $arrayValidator;\n\n    private ArrayShapeValidator $arrayShapeValidator;\n\n    private ObjectShapeValidator $objectShapeValidator;\n\n    private ConstValidator $constValidator;\n\n    /**\n     * Static map for fast validator resolution.\n     *\n     * @var array<string, TypeValidatorInterface>\n     */\n    private array $validatorMap;\n\n    public static function reset(): void\n    {\n    }\n\n    public function __construct()\n    {\n        $this->identifierValidator = new IdentifierValidator();\n        $this->genericValidator = new GenericValidator();\n        $this->unionValidator = new UnionValidator();\n        $this->intersectionValidator = new IntersectionValidator();\n        $this->nullableValidator = new NullableValidator();\n        $this->arrayValidator = new ArrayValidator();\n        $this->arrayShapeValidator = new ArrayShapeValidator();\n        $this->objectShapeValidator = new ObjectShapeValidator();\n        $this->constValidator = new ConstValidator();\n\n        $this->validatorMap = [\n            IdentifierTypeNode::class => $this->identifierValidator,\n            GenericTypeNode::class => $this->genericValidator,\n            UnionTypeNode::class => $this->unionValidator,\n            NullableTypeNode::class => $this->nullableValidator,\n            ArrayTypeNode::class => $this->arrayValidator,\n            ArrayShapeNode::class => $this->arrayShapeValidator,\n            ObjectShapeNode::class => $this->objectShapeValidator,\n            IntersectionTypeNode::class => $this->intersectionValidator,\n            ConstTypeNode::class => $this->constValidator,\n        ];\n    }\n\n    /**\n     * Validates a value against an AST TypeNode and returns an ErrorMessage on failure or null on success.\n     */\n    public function validate(mixed $value, TypeNode $node, string $context = '', bool $isSensitive = false): ?ErrorMessage\n    {\n        $validator = $this->validatorMap[$node::class] ?? null;\n        if ($validator === null) {\n            return null;\n        }\n\n        return $validator->validate($value, $node, $context, $this, $isSensitive);\n    }\n}\n","/typephp/src/Internal/Validator/UnionValidator.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Validator;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse Stringable;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\ErrorMessage;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Util\\ClassNameValidator;\n\n/**\n * @internal Class for validating union types like int | string.\n */\nfinal class UnionValidator implements TypeValidatorInterface\n{\n    public function validate(mixed $value, TypeNode $node, string $context, TypeValidatorRegistry $registry, bool $isSensitive = false): ?ErrorMessage\n    {\n        /** @var UnionTypeNode $unionNode */\n        $unionNode = $node;\n\n        foreach ($unionNode->types as $type) {\n            if ($type instanceof IdentifierTypeNode) {\n                $name = strtolower($type->name);\n                if ($name === 'object' && \\is_object($value)) {\n                    return null;\n                }\n                if (($name === 'int' || $name === 'integer') && \\is_int($value)) {\n                    return null;\n                }\n                if ($name === 'string' && \\is_string($value)) {\n                    return null;\n                }\n                if (($name === 'bool' || $name === 'boolean') && \\is_bool($value)) {\n                    return null;\n                }\n                if ($name === 'null' && $value === null) {\n                    return null;\n                }\n                if ($name === 'class-string' && \\is_string($value) && ClassNameValidator::isValidClassString($value)) {\n                    return null;\n                }\n            }\n        }\n\n        $deepErrors = [];\n        $discriminatorMatchedErrors = [];\n        $hasAnyDiscriminator = false;\n\n        foreach ($unionNode->types as $type) {\n            $err = $registry->validate($value, $type, $context, $isSensitive);\n            if ($err === null) {\n                return null;\n            }\n\n            $msg = $err->getMessage();\n\n            $isDeep = (\n                str_starts_with($msg, $context . '[') ||\n                str_starts_with($msg, $context . '->') ||\n                str_starts_with($msg, $context . ' is missing required') ||\n                str_starts_with($msg, $context . ' contains unsealed') ||\n                str_starts_with($msg, $context . ' property') ||\n                str_starts_with($msg, $context . ' key') ||\n                str_starts_with($msg, $context . ' value') ||\n                str_starts_with($msg, $context . ' extra key')\n            );\n\n            if ($isDeep) {\n                $deepErrors[] = $err;\n\n                $discStatus = self::checkDiscriminatorStatus($value, $type);\n                if ($discStatus['hasDiscriminator']) {\n                    $hasAnyDiscriminator = true;\n                    if ($discStatus['isMatched']) {\n                        $discriminatorMatchedErrors[] = $err;\n                    }\n                }\n            }\n        }\n\n        if (\\count($discriminatorMatchedErrors) > 0) {\n            return $discriminatorMatchedErrors[0];\n        }\n\n        if ($hasAnyDiscriminator) {\n            return ErrorFactory::createError($context . ' must be of type ' . $unionNode . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n        }\n\n        if (\\count($deepErrors) > 0) {\n            return $deepErrors[0];\n        }\n\n        return ErrorFactory::createError($context . ' must be of type ' . $unionNode . ', ' . TypeFormatter::formatGivenValue($value, $isSensitive) . ' given');\n    }\n\n    /**\n     * Inspects a type branch to see if it defines a discriminator field and whether the input value matches it.\n     *\n     * @return array{hasDiscriminator: bool, isMatched: bool}\n     */\n    private static function checkDiscriminatorStatus(mixed $value, TypeNode $type): array\n    {\n        if (\\is_array($value) && $type instanceof ArrayShapeNode) {\n            foreach ($type->items as $item) {\n                if ($item->valueType instanceof ConstTypeNode) {\n                    $key = null;\n                    if ($item->keyName instanceof ConstExprStringNode) {\n                        $key = $item->keyName->value;\n                    } elseif ($item->keyName instanceof IdentifierTypeNode) {\n                        $key = $item->keyName->name;\n                    } elseif ($item->keyName instanceof ConstExprIntegerNode) {\n                        $key = (int) $item->keyName->value;\n                    }\n\n                    if ($key !== null) {\n                        $expectedVal = (string) $item->valueType->constExpr;\n                        $expectedVal = trim($expectedVal, '\\'\"');\n\n                        if (isset($value[$key])) {\n                            $actualVal = $value[$key];\n                            $actualStr = \\is_scalar($actualVal) || $actualVal instanceof Stringable ? (string) $actualVal : null;\n\n                            if ($actualStr === $expectedVal) {\n                                return ['hasDiscriminator' => true, 'isMatched' => true];\n                            }\n\n                            return ['hasDiscriminator' => true, 'isMatched' => false];\n                        }\n                    }\n                }\n            }\n        }\n\n        if (\\is_object($value) && $type instanceof ObjectShapeNode) {\n            foreach ($type->items as $item) {\n                if ($item->valueType instanceof ConstTypeNode) {\n                    $prop = (string) $item->keyName;\n                    $expectedVal = (string) $item->valueType->constExpr;\n                    $expectedVal = trim($expectedVal, '\\'\"');\n\n                    // @phpstan-ignore property.dynamicName\n                    if (isset($value->$prop)) {\n                        // @phpstan-ignore property.dynamicName\n                        $actualVal = $value->$prop;\n                        $actualStr = \\is_scalar($actualVal) || $actualVal instanceof Stringable ? (string) $actualVal : null;\n\n                        if ($actualStr === $expectedVal) {\n                            return ['hasDiscriminator' => true, 'isMatched' => true];\n                        }\n\n                        return ['hasDiscriminator' => true, 'isMatched' => false];\n                    }\n                }\n            }\n        }\n\n        return ['hasDiscriminator' => false, 'isMatched' => false];\n    }\n}\n","/typephp/src/Internal/Wrapper/CallableWrapper.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Wrapper;\n\nuse Closure;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse ReflectionFunction;\nuse TypeError;\nuse TypePHP\\Exception\\TypeError as TypePHPTypeError;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Diagnostic\\TypeFormatter;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\CallerBoundaryResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * Wraps callables to enforce argument and return type contracts dynamically at runtime.\n *\n * @internal\n */\nfinal class CallableWrapper\n{\n    /**\n     * Safely checks if a value is callable without triggering PHP 8.2+ deprecation warnings\n     * on partially supported callables (e.g. 'static::method', ['static', 'method']).\n     */\n    public static function isCallable(mixed $value): bool\n    {\n        if ($value instanceof Closure) {\n            return true;\n        }\n\n        if (\\is_object($value)) {\n            return method_exists($value, '__invoke');\n        }\n\n        if (\\is_string($value)) {\n            if ($value === '' || str_starts_with($value, 'static::') || str_starts_with($value, 'self::') || str_starts_with($value, 'parent::')) {\n                return false;\n            }\n\n            return \\is_callable($value);\n        }\n\n        if (\\is_array($value)) {\n            if (! isset($value[0], $value[1]) || \\count($value) !== 2) {\n                return false;\n            }\n\n            if (\\is_string($value[0]) && \\in_array(strtolower($value[0]), ['static', 'self', 'parent'], true)) {\n                return false;\n            }\n\n            return \\is_callable($value);\n        }\n\n        return false;\n    }\n\n    /**\n     * Resolves callable contract metadata for a function parameter or return value and wraps the callable.\n     */\n    public static function wrap(string $function, string $paramName, mixed $callable, TypeValidatorRegistry $registry, object|string|null $thisOrClass = null): mixed\n    {\n        $contract = DocblockParser::parse($function);\n        $typeNode = ($paramName === 'return') ? ($contract['return'] ?? null) : ($contract['types'][$paramName] ?? null);\n        $aliases = $contract['aliases'] ?? [];\n        $templates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n\n        if ($typeNode instanceof IdentifierTypeNode && isset($aliases[$typeNode->name])) {\n            $typeNode = $aliases[$typeNode->name];\n        }\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $boundTemplates = TemplateManager::getBoundTemplates($function, $thisObj, $templates);\n\n        if ($typeNode !== null && (\\count($boundTemplates) > 0 || \\count($templates) > 0)) {\n            $typeNode = TemplateSubstitutor::substitute($typeNode, $boundTemplates, $templates);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $function, $thisObj);\n        }\n\n        $prefix = ($paramName === 'return') ? \"$function(): Return value\" : \"$function(): Callback \\$$paramName\";\n\n        if (self::isCallable($callable)) {\n            return self::wrapTypeNode($typeNode, $callable, $prefix, $registry);\n        }\n\n        if (\\is_array($callable) && $typeNode !== null) {\n            $innerCallableTypeNode = null;\n\n            if ($typeNode instanceof GenericTypeNode && \\in_array(strtolower($typeNode->type->name), ['list', 'array', 'iterable'], strict: true)) {\n                $innerCallableTypeNode = $typeNode->genericTypes[1] ?? $typeNode->genericTypes[0] ?? null;\n            } elseif ($typeNode instanceof ArrayTypeNode) {\n                $innerCallableTypeNode = $typeNode->type;\n            }\n\n            if ($innerCallableTypeNode instanceof CallableTypeNode) {\n                $wrappedArray = [];\n                foreach ($callable as $k => $item) {\n                    if (self::isCallable($item)) {\n                        $itemPrefix = $prefix . (\\is_int($k) ? \"[$k]\" : \"['$k']\");\n                        $wrappedArray[$k] = self::wrapTypeNode($innerCallableTypeNode, $item, $itemPrefix, $registry);\n                    } else {\n                        $wrappedArray[$k] = $item;\n                    }\n                }\n\n                return $wrappedArray;\n            }\n        }\n\n        return $callable;\n    }\n\n    /**\n     * Wraps a callable with runtime argument and return value type validation based on a CallableTypeNode AST.\n     */\n    public static function wrapTypeNode(?TypeNode $typeNode, mixed $callable, string $prefix, TypeValidatorRegistry $registry): mixed\n    {\n        if (! ($typeNode instanceof CallableTypeNode) || ! self::isCallable($callable)) {\n            return $callable;\n        }\n\n        $identifierName = strtolower(ltrim($typeNode->identifier->name, '\\\\'));\n        self::enforceClosureConstraints($identifierName, $callable, $prefix);\n\n        /** @var callable $callable */\n        return self::createDispatcherClosure($typeNode, $callable, $prefix, $registry);\n    }\n\n    /**\n     * Dispatches to a closure matching the exact by-reference signature of the callable.\n     */\n    private static function createDispatcherClosure(\n        CallableTypeNode $typeNode,\n        callable $callable,\n        string $prefix,\n        TypeValidatorRegistry $registry\n    ): Closure {\n        $hasAnyRef = false;\n        $isVariadicRef = false;\n        $refPattern = [];\n\n        foreach ($typeNode->parameters as $p) {\n            $refPattern[] = $p->isReference;\n            if ($p->isReference) {\n                $hasAnyRef = true;\n                if ($p->isVariadic) {\n                    $isVariadicRef = true;\n                }\n            }\n        }\n\n        if (! $hasAnyRef) {\n            return function (...$args) use ($callable, $typeNode, $registry, $prefix) {\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable(...$args);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        if ($isVariadicRef) {\n            return function (&...$args) use ($callable, $typeNode, $registry, $prefix) {\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable(...$args);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        if ($refPattern === [true]) {\n            return function (mixed &$a = null) use ($callable, $typeNode, $registry, $prefix) {\n                $args = [&$a];\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable($a);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        if ($refPattern === [true, false]) {\n            return function (mixed &$a = null, mixed $b = null) use ($callable, $typeNode, $registry, $prefix) {\n                $args = [&$a, $b];\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable($a, $b);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        if ($refPattern === [false, true]) {\n            return function (mixed $a = null, mixed &$b = null) use ($callable, $typeNode, $registry, $prefix) {\n                $args = [$a, &$b];\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable($a, $b);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        if ($refPattern === [true, true]) {\n            return function (mixed &$a = null, mixed &$b = null) use ($callable, $typeNode, $registry, $prefix) {\n                $args = [&$a, &$b];\n                self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n                try {\n                    $result = $callable($a, $b);\n                } catch (TypeError $e) {\n                    throw ErrorFactory::prepareException($e);\n                }\n\n                self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n                return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n            };\n        }\n\n        return function (&...$args) use ($callable, $typeNode, $registry, $prefix) {\n            self::validateCallbackArguments($typeNode, $args, $prefix, $registry, $callable);\n\n            try {\n                $result = $callable(...$args);\n            } catch (TypeError $e) {\n                throw ErrorFactory::prepareException($e);\n            }\n\n            self::validateCallbackByRefMutations($typeNode, $args, $prefix, $registry, $callable);\n\n            return self::validateCallbackReturn($typeNode, $result, $prefix, $registry, $callable);\n        };\n    }\n\n    private static function validateCallbackReturn(\n        CallableTypeNode $typeNode,\n        mixed $result,\n        string $prefix,\n        TypeValidatorRegistry $registry,\n        mixed $callable\n    ): mixed {\n        $isVoidReturn = ($typeNode->returnType instanceof IdentifierTypeNode)\n            && strtolower($typeNode->returnType->name) === 'void';\n\n        if (! $isVoidReturn) {\n            $err = $registry->validate($result, $typeNode->returnType, \"$prefix return value\");\n            if ($err !== null) {\n                if (! CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                    throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                }\n            }\n        }\n\n        if ($typeNode->returnType instanceof CallableTypeNode && self::isCallable($result)) {\n            $result = self::wrapTypeNode($typeNode->returnType, $result, \"$prefix: Returned callback\", $registry);\n        }\n\n        return $result;\n    }\n\n    /**\n     * Enforces strict Closure and static-closure constraints on the provided callable.\n     */\n    private static function enforceClosureConstraints(string $identifierName, mixed $callable, string $prefix): void\n    {\n        if (str_contains($identifierName, 'closure') && ! ($callable instanceof Closure)) {\n            if (CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                return;\n            }\n\n            throw ErrorFactory::prepareException(new TypePHPTypeError($prefix . ' must be of type Closure, ' . TypeFormatter::formatGivenValue($callable) . ' given'));\n        }\n\n        if (str_contains($identifierName, 'static') && $callable instanceof Closure) {\n            $refFunc = new ReflectionFunction($callable);\n            if ($refFunc->getClosureThis() !== null) {\n                if (CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                    return;\n                }\n\n                throw ErrorFactory::prepareException(new TypePHPTypeError($prefix . ' must be a static Closure (not bound to $this)'));\n            }\n        }\n    }\n\n    /**\n     * Validates variadic, positional, and named arguments passed into an intercepted callback.\n     *\n     * @param array<int|string, mixed> $args\n     */\n    private static function validateCallbackArguments(\n        CallableTypeNode $typeNode,\n        array &$args,\n        string $prefix,\n        TypeValidatorRegistry $registry,\n        mixed $callable = null\n    ): void {\n        $argValues = array_values($args);\n        $argCount = \\count($argValues);\n\n        foreach ($typeNode->parameters as $index => $paramNode) {\n            $rawParamName = ltrim($paramNode->parameterName ?? '', '$');\n\n            if ($paramNode->isVariadic) {\n                for ($vIdx = $index; $vIdx < $argCount; $vIdx++) {\n                    $err = $registry->validate($argValues[$vIdx], $paramNode->type, \"$prefix variadic argument #\" . ($vIdx + 1));\n                    if ($err !== null) {\n                        if ($callable !== null && CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                            continue;\n                        }\n\n                        throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                    }\n                }\n\n                break;\n            }\n\n            $val = null;\n            $hasVal = false;\n\n            if ($rawParamName !== '' && \\array_key_exists($rawParamName, $args)) {\n                $val = $args[$rawParamName];\n                $hasVal = true;\n            } elseif (\\array_key_exists($index, $argValues)) {\n                $val = $argValues[$index];\n                $hasVal = true;\n            }\n\n            if ($hasVal) {\n                $argLabel = $rawParamName !== '' ? \"\\$$rawParamName\" : ('argument #' . ($index + 1));\n                $err = $registry->validate($val, $paramNode->type, \"$prefix $argLabel\");\n                if ($err !== null) {\n                    if ($callable !== null && CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                        continue;\n                    }\n\n                    throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                }\n            }\n        }\n    }\n\n    /**\n     * Validates in-place reference mutations after the callback finishes execution.\n     *\n     * @param array<int|string, mixed> $args\n     */\n    private static function validateCallbackByRefMutations(\n        CallableTypeNode $typeNode,\n        array &$args,\n        string $prefix,\n        TypeValidatorRegistry $registry,\n        mixed $callable = null\n    ): void {\n        $argValues = array_values($args);\n        $argCount = \\count($argValues);\n\n        foreach ($typeNode->parameters as $index => $paramNode) {\n            if (! $paramNode->isReference) {\n                continue;\n            }\n\n            $rawParamName = ltrim($paramNode->parameterName ?? '', '$');\n\n            if ($paramNode->isVariadic) {\n                for ($vIdx = $index; $vIdx < $argCount; $vIdx++) {\n                    $err = $registry->validate($argValues[$vIdx], $paramNode->type, \"$prefix variadic argument #\" . ($vIdx + 1));\n                    if ($err !== null) {\n                        if ($callable !== null && CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                            continue;\n                        }\n\n                        throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                    }\n                }\n\n                break;\n            }\n\n            $val = null;\n            $hasVal = false;\n\n            if ($rawParamName !== '' && \\array_key_exists($rawParamName, $args)) {\n                $val = $args[$rawParamName];\n                $hasVal = true;\n            } elseif (\\array_key_exists($index, $argValues)) {\n                $val = $argValues[$index];\n                $hasVal = true;\n            }\n\n            if ($hasVal) {\n                $argLabel = $rawParamName !== '' ? \"\\$$rawParamName\" : ('argument #' . ($index + 1));\n                $err = $registry->validate($val, $paramNode->type, \"$prefix $argLabel\");\n                if ($err !== null) {\n                    if ($callable !== null && CallerBoundaryResolver::shouldBypassCallback($callable, $prefix)) {\n                        continue;\n                    }\n\n                    throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                }\n            }\n        }\n    }\n}\n","/typephp/src/Internal/Wrapper/IterableWrapper.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Wrapper;\n\nuse Generator;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse TypePHP\\Exception\\TypeError as TypePHPTypeError;\nuse TypePHP\\Internal\\Diagnostic\\ErrorFactory;\nuse TypePHP\\Internal\\Docblock\\DocblockParser;\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Generics\\TemplateSubstitutor;\nuse TypePHP\\Internal\\Resolver\\CallerBoundaryResolver;\nuse TypePHP\\Internal\\Resolver\\SpecialTypeResolver;\nuse TypePHP\\Internal\\Validator\\TypeValidatorRegistry;\n\n/**\n * Wraps Traversable objects and Generators to evaluate key and value type constraints lazily during iteration.\n *\n * @internal\n */\nfinal class IterableWrapper\n{\n    /**\n     * Wraps Traversable iterators and Generators to lazily validate keys and values during iteration.\n     */\n    public static function wrap(string $function, string $paramName, mixed $iterable, TypeValidatorRegistry $registry, object|string|null $thisOrClass = null): mixed\n    {\n        if (! is_iterable($iterable)) {\n            return $iterable;\n        }\n\n        if (\\is_array($iterable) && $paramName !== 'return') {\n            return $iterable;\n        }\n\n        $contract = DocblockParser::parse($function);\n        $typeNode = ($paramName === 'return') ? ($contract['return'] ?? null) : ($contract['types'][$paramName] ?? null);\n\n        if ($typeNode === null) {\n            return $iterable;\n        }\n\n        $aliases = $contract['aliases'] ?? [];\n        $templates = [...($contract['classTemplates'] ?? []), ...($contract['templates'] ?? [])];\n\n        $thisObj = \\is_object($thisOrClass) ? $thisOrClass : null;\n        $boundTemplates = TemplateManager::getBoundTemplates($function, $thisObj, $templates);\n\n        if (\\count($boundTemplates) > 0 || \\count($templates) > 0) {\n            $typeNode = TemplateSubstitutor::substitute($typeNode, $boundTemplates, $templates);\n            $typeNode = SpecialTypeResolver::resolve($typeNode, $function, $thisObj);\n        }\n\n        $baseName = '';\n        if ($typeNode instanceof IdentifierTypeNode) {\n            $baseName = strtolower(ltrim($typeNode->name, '\\\\'));\n        } elseif ($typeNode instanceof GenericTypeNode) {\n            $baseName = strtolower(ltrim($typeNode->type->name, '\\\\'));\n        }\n\n        $standardIterables = ['iterable', 'traversable', 'iterator', 'generator'];\n        if (! \\in_array($baseName, $standardIterables, strict: true)) {\n            return $iterable;\n        }\n\n        [$keyTypeNode, $itemTypeNode] = self::extractKeyAndItemTypeNodes($typeNode, $aliases);\n\n        if ($keyTypeNode === null && $itemTypeNode === null) {\n            return $iterable;\n        }\n\n        $prefix = ($paramName === 'return') ? \"$function(): Return iterator\" : \"$function(): Iterator \\$$paramName\";\n        $typeCheckCallback = self::createValidationCallback($registry, $keyTypeNode, $itemTypeNode, $prefix, $function);\n\n        if (\\is_array($iterable)) {\n            return self::wrapGenerator((function () use ($iterable) {\n                yield from $iterable;\n            })(), $typeCheckCallback);\n        }\n\n        if (! ($iterable instanceof Generator)) {\n            return new IteratorProxy($iterable, $typeCheckCallback);\n        }\n\n        return self::wrapGenerator($iterable, $typeCheckCallback);\n    }\n\n    /**\n     * Extracts key and value TypeNodes from an iterable type node AST or type alias.\n     *\n     * @param array<string, TypeNode> $aliases\n     *\n     * @return array{?TypeNode, ?TypeNode}\n     */\n    private static function extractKeyAndItemTypeNodes(?TypeNode $typeNode, array $aliases): array\n    {\n        if ($typeNode instanceof IdentifierTypeNode && isset($aliases[$typeNode->name])) {\n            $typeNode = $aliases[$typeNode->name];\n        }\n\n        $itemTypeNode = null;\n        $keyTypeNode = null;\n\n        if ($typeNode instanceof GenericTypeNode) {\n            $typesCount = \\count($typeNode->genericTypes);\n            if ($typesCount === 1) {\n                $itemTypeNode = $typeNode->genericTypes[0];\n            } elseif ($typesCount >= 2) {\n                $keyTypeNode = $typeNode->genericTypes[0];\n                $itemTypeNode = $typeNode->genericTypes[1];\n            }\n        } elseif ($typeNode instanceof ArrayTypeNode) {\n            $itemTypeNode = $typeNode->type;\n        }\n\n        return [$keyTypeNode, $itemTypeNode];\n    }\n\n    /**\n     * Builds a validation closure to check yielded keys and values during iteration.\n     *\n     * @return \\Closure(mixed, mixed): void\n     */\n    private static function createValidationCallback(\n        TypeValidatorRegistry $registry,\n        ?TypeNode $keyTypeNode,\n        ?TypeNode $itemTypeNode,\n        string $prefix,\n        string $function = ''\n    ): \\Closure {\n        return function (mixed $key, mixed $value) use ($registry, $keyTypeNode, $itemTypeNode, $prefix, $function): void {\n            if ($keyTypeNode !== null && $key !== null) {\n                $err = $registry->validate($key, $keyTypeNode, \"$prefix key\");\n                if ($err !== null) {\n                    if ($function !== '' && CallerBoundaryResolver::shouldBypass($function)) {\n                        return;\n                    }\n\n                    if (CallerBoundaryResolver::isCallerVendor()) {\n                        return;\n                    }\n\n                    throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                }\n            }\n\n            if ($itemTypeNode !== null) {\n                $err = $registry->validate($value, $itemTypeNode, \"$prefix value\");\n                if ($err !== null) {\n                    if ($function !== '' && CallerBoundaryResolver::shouldBypass($function)) {\n                        return;\n                    }\n\n                    if (CallerBoundaryResolver::isCallerVendor()) {\n                        return;\n                    }\n\n                    throw ErrorFactory::prepareException(new TypePHPTypeError($err->getMessage()));\n                }\n            }\n        };\n    }\n\n    /**\n     * Wraps an iterable generator in an interceptor generator to evaluate type checks on each yield.\n     *\n     * @param iterable<mixed, mixed> $iterable\n     * @param \\Closure(mixed, mixed): void $typeCheckCallback\n     *\n     * @return Generator<mixed, mixed>\n     */\n    private static function wrapGenerator(iterable $iterable, \\Closure $typeCheckCallback): Generator\n    {\n        foreach ($iterable as $key => $value) {\n            $typeCheckCallback($key, $value);\n            yield $key => $value;\n        }\n    }\n}\n","/typephp/src/Internal/Wrapper/IteratorProxy.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP\\Internal\\Wrapper;\n\nuse Countable;\nuse Iterator;\nuse IteratorAggregate;\nuse OuterIterator;\nuse Traversable;\n\n/**\n * @internal Proxy wrapper around Traversable objects to evaluate type contracts on current items while preserving rewindability, Countable support, and method forwarding.\n *\n * @implements OuterIterator<mixed, mixed>\n */\nfinal class IteratorProxy implements OuterIterator, Countable\n{\n    private Iterator $inner;\n\n    /**\n     * @param Traversable<mixed, mixed> $iterable\n     * @param \\Closure(mixed, mixed): void $typeCheckCallback\n     */\n    public function __construct(\n        Traversable $iterable,\n        private \\Closure $typeCheckCallback\n    ) {\n        $this->inner = self::resolveIterator($iterable);\n    }\n\n    /**\n     * Recursively unwraps IteratorAggregate instances until a concrete Iterator is found.\n     *\n     * @param Traversable<mixed, mixed> $iterable\n     */\n    private static function resolveIterator(Traversable $iterable): Iterator\n    {\n        while ($iterable instanceof IteratorAggregate) {\n            $iterable = $iterable->getIterator();\n        }\n\n        /** @var Iterator $iterable */\n        return $iterable;\n    }\n\n    public function rewind(): void\n    {\n        $this->inner->rewind();\n    }\n\n    public function valid(): bool\n    {\n        return $this->inner->valid();\n    }\n\n    public function current(): mixed\n    {\n        $key = $this->inner->key();\n        $val = $this->inner->current();\n        ($this->typeCheckCallback)($key, $val);\n\n        return $val;\n    }\n\n    public function key(): mixed\n    {\n        return $this->inner->key();\n    }\n\n    public function next(): void\n    {\n        $this->inner->next();\n    }\n\n    public function getInnerIterator(): Iterator\n    {\n        return $this->inner;\n    }\n\n    public function count(): int\n    {\n        if ($this->inner instanceof Countable) {\n            return $this->inner->count();\n        }\n\n        return iterator_count($this->inner);\n    }\n\n    /**\n     * @param array<int|string, mixed> $args\n     */\n    public function __call(string $method, array $args): mixed\n    {\n        // @phpstan-ignore method.dynamicName\n        return $this->inner->$method(...$args);\n    }\n}\n","/typephp/src/TypePHP.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP;\n\nuse TypePHP\\Internal\\Generics\\TemplateManager;\nuse TypePHP\\Internal\\Io\\StreamWrapper;\nuse TypePHP\\Internal\\Util\\Config;\n\nfinal class TypePHP\n{\n    /**\n     * Boots TypePHP and registers the custom StreamWrapper protocol.\n     */\n    public static function boot(): void\n    {\n        StreamWrapper::register(Config::get());\n    }\n\n    /**\n     * Returns the bound generic type for a template parameter on an object instance (Reified Generics).\n     * If no template name is specified on a single-template class, returns the bound type automatically.\n     */\n    public static function getGenericType(object $instance, ?string $templateName = null): ?string\n    {\n        $types = self::getGenericTypes($instance);\n        if (\\count($types) === 0) {\n            return null;\n        }\n\n        if ($templateName !== null && isset($types[$templateName])) {\n            return $types[$templateName];\n        }\n\n        if (\\count($types) === 1) {\n            return reset($types);\n        }\n\n        return $types['T'] ?? $types['TValue'] ?? $types['TElement'] ?? $types['V'] ?? null;\n    }\n\n    /**\n     * Returns all bound generic template parameters for an object instance as a key-value array.\n     *\n     * @return array<string, string>\n     */\n    public static function getGenericTypes(object $instance): array\n    {\n        $boundNodes = TemplateManager::getBoundTemplatesForInstance($instance);\n        $types = [];\n\n        foreach ($boundNodes as $name => $node) {\n            $types[$name] = (string) $node;\n        }\n\n        return $types;\n    }\n\n    /**\n     * Returns the declared variance ('covariant', 'contravariant', or 'invariant') for a template parameter on an object instance.\n     */\n    public static function getGenericVariance(object $instance, ?string $templateName = null): string\n    {\n        $variances = self::getGenericVariances($instance);\n        if (\\count($variances) === 0) {\n            return 'invariant';\n        }\n\n        if ($templateName !== null && isset($variances[$templateName])) {\n            return $variances[$templateName];\n        }\n\n        if (\\count($variances) === 1) {\n            return reset($variances);\n        }\n\n        return $variances['T'] ?? $variances['TValue'] ?? $variances['TElement'] ?? $variances['V'] ?? 'invariant';\n    }\n\n    /**\n     * Returns all declared template variances ('covariant', 'contravariant', or 'invariant') for an object instance.\n     *\n     * @return array<string, string>\n     */\n    public static function getGenericVariances(object $instance): array\n    {\n        return TemplateManager::getTemplateVariances($instance);\n    }\n\n    /**\n     * Returns the current resolved global configuration settings.\n     *\n     * @return array<string, mixed>\n     */\n    public static function getConfig(): array\n    {\n        return Config::get();\n    }\n\n    /**\n     * Dynamically overrides configuration settings at runtime.\n     * Useful for test environments and custom setup scripts.\n     *\n     * @param array<string, mixed> $config\n     */\n    public static function setConfig(array $config): void\n    {\n        Config::set($config);\n    }\n\n    /**\n     * Resets the configuration cache back to typephp.php defaults.\n     * Useful for test isolation between test runs.\n     */\n    public static function resetConfig(): void\n    {\n        Config::reset();\n    }\n}\n","/typephp/src/bootstrap.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace TypePHP;\n\nif (class_exists(TypePHP::class) && ! \\defined('TYPEPHP_BOOTED')) {\n    \\define('TYPEPHP_BOOTED', true);\n\n    $isDisabledEnv = getenv('TYPEPHP_DISABLE') !== false && filter_var(getenv('TYPEPHP_DISABLE'), FILTER_VALIDATE_BOOLEAN);\n    $isDisabledConst = \\defined('TYPEPHP_DISABLE') && TYPEPHP_DISABLE;\n\n    $isTooling = false;\n    $binary = '';\n\n    if (isset($_SERVER['argv']) && \\is_array($_SERVER['argv']) && \\count($_SERVER['argv']) > 0) {\n        $candidate = $_SERVER['argv'][0];\n\n        if (\\is_string($candidate)) {\n            $baseArg0 = strtolower(basename(str_replace('\\\\', '/', $candidate)));\n            if (\\in_array($baseArg0, ['php', 'php.exe', 'php-cgi', 'php-fpm'], true) && isset($_SERVER['argv'][1]) && \\is_string($_SERVER['argv'][1])) {\n                $candidate = $_SERVER['argv'][1];\n            }\n\n            $rawBinary = strtolower(basename(str_replace('\\\\', '/', $candidate)));\n            $binary = preg_replace('/\\.(phar|bat|exe|cmd)$/i', '', $rawBinary) ?? $rawBinary;\n\n            $toolingBinaries = [\n                'phpstan' => true,\n                'psalm' => true,\n                'php-cs-fixer' => true,\n                'phpcs' => true,\n                'phpcbf' => true,\n                'pint' => true,\n                'rector' => true,\n                'mago' => true,\n                'composer' => true,\n                'deptrac' => true,\n                'phan' => true,\n                'paratest' => true,\n            ];\n\n            $isTooling = isset($toolingBinaries[$binary]);\n        }\n    }\n\n    $isParallelParent = false;\n    if (isset($_SERVER['argv']) && \\is_array($_SERVER['argv'])) {\n        $hasParallelArg = false;\n        foreach ($_SERVER['argv'] as $arg) {\n            if (\\is_string($arg) && (str_starts_with($arg, '--parallel') || $arg === '-p' || str_starts_with($arg, '--processes'))) {\n                $hasParallelArg = true;\n\n                break;\n            }\n        }\n\n        $isParallelParent = ($binary === 'paratest') || ($binary === 'pest' && $hasParallelArg);\n\n        if (getenv('TEST_TOKEN') !== false || getenv('PARATEST') !== false || getenv('PEST_PARALLEL_WORKER_ID') !== false) {\n            $isParallelParent = false;\n        }\n    }\n\n    if (! $isDisabledEnv && ! $isDisabledConst && ! $isTooling && ! $isParallelParent) {\n        TypePHP::boot();\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/ClassConst.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Const_;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Stmt;\n\nclass ClassConst implements PhpParser\\Builder {\n    protected int $flags = 0;\n    /** @var array<string, mixed> */\n    protected array $attributes = [];\n    /** @var list<Const_> */\n    protected array $constants = [];\n\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n    /** @var Identifier|Node\\Name|Node\\ComplexType|null */\n    protected ?Node $type = null;\n\n    /**\n     * Creates a class constant builder\n     *\n     * @param string|Identifier $name Name\n     * @param Node\\Expr|bool|null|int|float|string|array|\\UnitEnum $value Value\n     */\n    public function __construct($name, $value) {\n        $this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];\n    }\n\n    /**\n     * Add another constant to const group\n     *\n     * @param string|Identifier $name Name\n     * @param Node\\Expr|bool|null|int|float|string|array|\\UnitEnum $value Value\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addConst($name, $value) {\n        $this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value));\n\n        return $this;\n    }\n\n    /**\n     * Makes the constant public.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePublic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the constant protected.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtected() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);\n\n        return $this;\n    }\n\n    /**\n     * Makes the constant private.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivate() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);\n\n        return $this;\n    }\n\n    /**\n     * Makes the constant final.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeFinal() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);\n\n        return $this;\n    }\n\n    /**\n     * Sets doc comment for the constant.\n     *\n     * @param PhpParser\\Comment\\Doc|string $docComment Doc comment to set\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDocComment($docComment) {\n        $this->attributes = [\n            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]\n        ];\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Sets the constant type.\n     *\n     * @param string|Node\\Name|Identifier|Node\\ComplexType $type\n     *\n     * @return $this\n     */\n    public function setType($type) {\n        $this->type = BuilderHelpers::normalizeType($type);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built class node.\n     *\n     * @return Stmt\\ClassConst The built constant node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\ClassConst(\n            $this->constants,\n            $this->flags,\n            $this->attributes,\n            $this->attributeGroups,\n            $this->type\n        );\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Class_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Stmt;\n\nclass Class_ extends Declaration {\n    protected string $name;\n    protected ?Name $extends = null;\n    /** @var list<Name> */\n    protected array $implements = [];\n    protected int $flags = 0;\n    /** @var list<Stmt\\TraitUse> */\n    protected array $uses = [];\n    /** @var list<Stmt\\ClassConst> */\n    protected array $constants = [];\n    /** @var list<Stmt\\Property> */\n    protected array $properties = [];\n    /** @var list<Stmt\\ClassMethod> */\n    protected array $methods = [];\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates a class builder.\n     *\n     * @param string $name Name of the class\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Extends a class.\n     *\n     * @param Name|string $class Name of class to extend\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function extend($class) {\n        $this->extends = BuilderHelpers::normalizeName($class);\n\n        return $this;\n    }\n\n    /**\n     * Implements one or more interfaces.\n     *\n     * @param Name|string ...$interfaces Names of interfaces to implement\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function implement(...$interfaces) {\n        foreach ($interfaces as $interface) {\n            $this->implements[] = BuilderHelpers::normalizeName($interface);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Makes the class abstract.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeAbstract() {\n        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::ABSTRACT);\n\n        return $this;\n    }\n\n    /**\n     * Makes the class final.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeFinal() {\n        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL);\n\n        return $this;\n    }\n\n    /**\n     * Makes the class readonly.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeReadonly() {\n        $this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::READONLY);\n\n        return $this;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Stmt|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $stmt = BuilderHelpers::normalizeNode($stmt);\n\n        if ($stmt instanceof Stmt\\Property) {\n            $this->properties[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassMethod) {\n            $this->methods[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\TraitUse) {\n            $this->uses[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassConst) {\n            $this->constants[] = $stmt;\n        } else {\n            throw new \\LogicException(sprintf('Unexpected node of type \"%s\"', $stmt->getType()));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built class node.\n     *\n     * @return Stmt\\Class_ The built class node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\Class_($this->name, [\n            'flags' => $this->flags,\n            'extends' => $this->extends,\n            'implements' => $this->implements,\n            'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),\n            'attrGroups' => $this->attributeGroups,\n        ], $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Declaration.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\n\nabstract class Declaration implements PhpParser\\Builder {\n    /** @var array<string, mixed> */\n    protected array $attributes = [];\n\n    /**\n     * Adds a statement.\n     *\n     * @param PhpParser\\Node\\Stmt|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    abstract public function addStmt($stmt);\n\n    /**\n     * Adds multiple statements.\n     *\n     * @param (PhpParser\\Node\\Stmt|PhpParser\\Builder)[] $stmts The statements to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmts(array $stmts) {\n        foreach ($stmts as $stmt) {\n            $this->addStmt($stmt);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Sets doc comment for the declaration.\n     *\n     * @param PhpParser\\Comment\\Doc|string $docComment Doc comment to set\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDocComment($docComment) {\n        $this->attributes['comments'] = [\n            BuilderHelpers::normalizeDocComment($docComment)\n        ];\n\n        return $this;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/EnumCase.php":"<?php\n\ndeclare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Stmt;\n\nclass EnumCase implements PhpParser\\Builder {\n    /** @var Identifier|string */\n    protected $name;\n    protected ?Node\\Expr $value = null;\n    /** @var array<string, mixed> */\n    protected array $attributes = [];\n\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates an enum case builder.\n     *\n     * @param string|Identifier $name Name\n     */\n    public function __construct($name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Sets the value.\n     *\n     * @param Node\\Expr|string|int $value\n     *\n     * @return $this\n     */\n    public function setValue($value) {\n        $this->value = BuilderHelpers::normalizeValue($value);\n\n        return $this;\n    }\n\n    /**\n     * Sets doc comment for the constant.\n     *\n     * @param PhpParser\\Comment\\Doc|string $docComment Doc comment to set\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDocComment($docComment) {\n        $this->attributes = [\n            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]\n        ];\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built enum case node.\n     *\n     * @return Stmt\\EnumCase The built constant node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\EnumCase(\n            $this->name,\n            $this->value,\n            $this->attributeGroups,\n            $this->attributes\n        );\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Enum_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Stmt;\n\nclass Enum_ extends Declaration {\n    protected string $name;\n    protected ?Identifier $scalarType = null;\n    /** @var list<Name> */\n    protected array $implements = [];\n    /** @var list<Stmt\\TraitUse> */\n    protected array $uses = [];\n    /** @var list<Stmt\\EnumCase> */\n    protected array $enumCases = [];\n    /** @var list<Stmt\\ClassConst> */\n    protected array $constants = [];\n    /** @var list<Stmt\\ClassMethod> */\n    protected array $methods = [];\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates an enum builder.\n     *\n     * @param string $name Name of the enum\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Sets the scalar type.\n     *\n     * @param string|Identifier $scalarType\n     *\n     * @return $this\n     */\n    public function setScalarType($scalarType) {\n        $this->scalarType = BuilderHelpers::normalizeType($scalarType);\n\n        return $this;\n    }\n\n    /**\n     * Implements one or more interfaces.\n     *\n     * @param Name|string ...$interfaces Names of interfaces to implement\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function implement(...$interfaces) {\n        foreach ($interfaces as $interface) {\n            $this->implements[] = BuilderHelpers::normalizeName($interface);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Stmt|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $stmt = BuilderHelpers::normalizeNode($stmt);\n\n        if ($stmt instanceof Stmt\\EnumCase) {\n            $this->enumCases[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassMethod) {\n            $this->methods[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\TraitUse) {\n            $this->uses[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassConst) {\n            $this->constants[] = $stmt;\n        } else {\n            throw new \\LogicException(sprintf('Unexpected node of type \"%s\"', $stmt->getType()));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built class node.\n     *\n     * @return Stmt\\Enum_ The built enum node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\Enum_($this->name, [\n            'scalarType' => $this->scalarType,\n            'implements' => $this->implements,\n            'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods),\n            'attrGroups' => $this->attributeGroups,\n        ], $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/FunctionLike.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\n\nabstract class FunctionLike extends Declaration {\n    protected bool $returnByRef = false;\n    /** @var Node\\Param[] */\n    protected array $params = [];\n\n    /** @var Node\\Identifier|Node\\Name|Node\\ComplexType|null */\n    protected ?Node $returnType = null;\n\n    /**\n     * Make the function return by reference.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeReturnByRef() {\n        $this->returnByRef = true;\n\n        return $this;\n    }\n\n    /**\n     * Adds a parameter.\n     *\n     * @param Node\\Param|Param $param The parameter to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addParam($param) {\n        $param = BuilderHelpers::normalizeNode($param);\n\n        if (!$param instanceof Node\\Param) {\n            throw new \\LogicException(sprintf('Expected parameter node, got \"%s\"', $param->getType()));\n        }\n\n        $this->params[] = $param;\n\n        return $this;\n    }\n\n    /**\n     * Adds multiple parameters.\n     *\n     * @param (Node\\Param|Param)[] $params The parameters to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addParams(array $params) {\n        foreach ($params as $param) {\n            $this->addParam($param);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Sets the return type for PHP 7.\n     *\n     * @param string|Node\\Name|Node\\Identifier|Node\\ComplexType $type\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setReturnType($type) {\n        $this->returnType = BuilderHelpers::normalizeType($type);\n\n        return $this;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Function_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass Function_ extends FunctionLike {\n    protected string $name;\n    /** @var list<Stmt> */\n    protected array $stmts = [];\n\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates a function builder.\n     *\n     * @param string $name Name of the function\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Node|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built function node.\n     *\n     * @return Stmt\\Function_ The built function node\n     */\n    public function getNode(): Node {\n        return new Stmt\\Function_($this->name, [\n            'byRef'      => $this->returnByRef,\n            'params'     => $this->params,\n            'returnType' => $this->returnType,\n            'stmts'      => $this->stmts,\n            'attrGroups' => $this->attributeGroups,\n        ], $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Interface_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Stmt;\n\nclass Interface_ extends Declaration {\n    protected string $name;\n    /** @var list<Name> */\n    protected array $extends = [];\n    /** @var list<Stmt\\ClassConst> */\n    protected array $constants = [];\n    /** @var list<Stmt\\ClassMethod> */\n    protected array $methods = [];\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates an interface builder.\n     *\n     * @param string $name Name of the interface\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Extends one or more interfaces.\n     *\n     * @param Name|string ...$interfaces Names of interfaces to extend\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function extend(...$interfaces) {\n        foreach ($interfaces as $interface) {\n            $this->extends[] = BuilderHelpers::normalizeName($interface);\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Stmt|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $stmt = BuilderHelpers::normalizeNode($stmt);\n\n        if ($stmt instanceof Stmt\\ClassConst) {\n            $this->constants[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassMethod) {\n            // we erase all statements in the body of an interface method\n            $stmt->stmts = null;\n            $this->methods[] = $stmt;\n        } else {\n            throw new \\LogicException(sprintf('Unexpected node of type \"%s\"', $stmt->getType()));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built interface node.\n     *\n     * @return Stmt\\Interface_ The built interface node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\Interface_($this->name, [\n            'extends' => $this->extends,\n            'stmts' => array_merge($this->constants, $this->methods),\n            'attrGroups' => $this->attributeGroups,\n        ], $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Method.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass Method extends FunctionLike {\n    protected string $name;\n\n    protected int $flags = 0;\n\n    /** @var list<Stmt>|null */\n    protected ?array $stmts = [];\n\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates a method builder.\n     *\n     * @param string $name Name of the method\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Makes the method public.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePublic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the method protected.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtected() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);\n\n        return $this;\n    }\n\n    /**\n     * Makes the method private.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivate() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);\n\n        return $this;\n    }\n\n    /**\n     * Makes the method static.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeStatic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the method abstract.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeAbstract() {\n        if (!empty($this->stmts)) {\n            throw new \\LogicException('Cannot make method with statements abstract');\n        }\n\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);\n        $this->stmts = null; // abstract methods don't have statements\n\n        return $this;\n    }\n\n    /**\n     * Makes the method final.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeFinal() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);\n\n        return $this;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Node|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        if (null === $this->stmts) {\n            throw new \\LogicException('Cannot add statements to an abstract method');\n        }\n\n        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built method node.\n     *\n     * @return Stmt\\ClassMethod The built method node\n     */\n    public function getNode(): Node {\n        return new Stmt\\ClassMethod($this->name, [\n            'flags'      => $this->flags,\n            'byRef'      => $this->returnByRef,\n            'params'     => $this->params,\n            'returnType' => $this->returnType,\n            'stmts'      => $this->stmts,\n            'attrGroups' => $this->attributeGroups,\n        ], $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Namespace_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass Namespace_ extends Declaration {\n    private ?Node\\Name $name;\n    /** @var Stmt[] */\n    private array $stmts = [];\n\n    /**\n     * Creates a namespace builder.\n     *\n     * @param Node\\Name|string|null $name Name of the namespace\n     */\n    public function __construct($name) {\n        $this->name = null !== $name ? BuilderHelpers::normalizeName($name) : null;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Node|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $this->stmts[] = BuilderHelpers::normalizeStmt($stmt);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built node.\n     *\n     * @return Stmt\\Namespace_ The built node\n     */\n    public function getNode(): Node {\n        return new Stmt\\Namespace_($this->name, $this->stmts, $this->attributes);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Param.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\n\nclass Param implements PhpParser\\Builder {\n    protected string $name;\n    protected ?Node\\Expr $default = null;\n    /** @var Node\\Identifier|Node\\Name|Node\\ComplexType|null */\n    protected ?Node $type = null;\n    protected bool $byRef = false;\n    protected int $flags = 0;\n    protected bool $variadic = false;\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates a parameter builder.\n     *\n     * @param string $name Name of the parameter\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Sets default value for the parameter.\n     *\n     * @param mixed $value Default value to use\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDefault($value) {\n        $this->default = BuilderHelpers::normalizeValue($value);\n\n        return $this;\n    }\n\n    /**\n     * Sets type for the parameter.\n     *\n     * @param string|Node\\Name|Node\\Identifier|Node\\ComplexType $type Parameter type\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setType($type) {\n        $this->type = BuilderHelpers::normalizeType($type);\n        if ($this->type == 'void') {\n            throw new \\LogicException('Parameter type cannot be void');\n        }\n\n        return $this;\n    }\n\n    /**\n     * Make the parameter accept the value by reference.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeByRef() {\n        $this->byRef = true;\n\n        return $this;\n    }\n\n    /**\n     * Make the parameter variadic\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeVariadic() {\n        $this->variadic = true;\n\n        return $this;\n    }\n\n    /**\n     * Makes the (promoted) parameter public.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePublic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the (promoted) parameter protected.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtected() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);\n\n        return $this;\n    }\n\n    /**\n     * Makes the (promoted) parameter private.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivate() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);\n\n        return $this;\n    }\n\n    /**\n     * Makes the (promoted) parameter readonly.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeReadonly() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);\n\n        return $this;\n    }\n\n    /**\n     * Gives the promoted property private(set) visibility.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivateSet() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);\n\n        return $this;\n    }\n\n    /**\n     * Gives the promoted property protected(set) visibility.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtectedSet() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built parameter node.\n     *\n     * @return Node\\Param The built parameter node\n     */\n    public function getNode(): Node {\n        return new Node\\Param(\n            new Node\\Expr\\Variable($this->name),\n            $this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups\n        );\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Property.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\Node\\ComplexType;\n\nclass Property implements PhpParser\\Builder {\n    protected string $name;\n\n    protected int $flags = 0;\n\n    protected ?Node\\Expr $default = null;\n    /** @var array<string, mixed> */\n    protected array $attributes = [];\n    /** @var null|Identifier|Name|ComplexType */\n    protected ?Node $type = null;\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n    /** @var list<Node\\PropertyHook> */\n    protected array $hooks = [];\n\n    /**\n     * Creates a property builder.\n     *\n     * @param string $name Name of the property\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Makes the property public.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePublic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property protected.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtected() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property private.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivate() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property static.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeStatic() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property readonly.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeReadonly() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property abstract. Requires at least one property hook to be specified as well.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeAbstract() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);\n\n        return $this;\n    }\n\n    /**\n     * Makes the property final.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeFinal() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);\n\n        return $this;\n    }\n\n    /**\n     * Gives the property private(set) visibility.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivateSet() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE_SET);\n\n        return $this;\n    }\n\n    /**\n     * Gives the property protected(set) visibility.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtectedSet() {\n        $this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED_SET);\n\n        return $this;\n    }\n\n    /**\n     * Sets default value for the property.\n     *\n     * @param mixed $value Default value to use\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDefault($value) {\n        $this->default = BuilderHelpers::normalizeValue($value);\n\n        return $this;\n    }\n\n    /**\n     * Sets doc comment for the property.\n     *\n     * @param PhpParser\\Comment\\Doc|string $docComment Doc comment to set\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function setDocComment($docComment) {\n        $this->attributes = [\n            'comments' => [BuilderHelpers::normalizeDocComment($docComment)]\n        ];\n\n        return $this;\n    }\n\n    /**\n     * Sets the property type for PHP 7.4+.\n     *\n     * @param string|Name|Identifier|ComplexType $type\n     *\n     * @return $this\n     */\n    public function setType($type) {\n        $this->type = BuilderHelpers::normalizeType($type);\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Adds a property hook.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addHook(Node\\PropertyHook $hook) {\n        $this->hooks[] = $hook;\n\n        return $this;\n    }\n\n    /**\n     * Returns the built class node.\n     *\n     * @return Stmt\\Property The built property node\n     */\n    public function getNode(): PhpParser\\Node {\n        if ($this->flags & Modifiers::ABSTRACT && !$this->hooks) {\n            throw new PhpParser\\Error('Only hooked properties may be declared abstract');\n        }\n\n        return new Stmt\\Property(\n            $this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,\n            [\n                new Node\\PropertyItem($this->name, $this->default)\n            ],\n            $this->attributes,\n            $this->type,\n            $this->attributeGroups,\n            $this->hooks\n        );\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser\\Builder;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass TraitUse implements Builder {\n    /** @var Node\\Name[] */\n    protected array $traits = [];\n    /** @var Stmt\\TraitUseAdaptation[] */\n    protected array $adaptations = [];\n\n    /**\n     * Creates a trait use builder.\n     *\n     * @param Node\\Name|string ...$traits Names of used traits\n     */\n    public function __construct(...$traits) {\n        foreach ($traits as $trait) {\n            $this->and($trait);\n        }\n    }\n\n    /**\n     * Adds used trait.\n     *\n     * @param Node\\Name|string $trait Trait name\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function and($trait) {\n        $this->traits[] = BuilderHelpers::normalizeName($trait);\n        return $this;\n    }\n\n    /**\n     * Adds trait adaptation.\n     *\n     * @param Stmt\\TraitUseAdaptation|Builder\\TraitUseAdaptation $adaptation Trait adaptation\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function with($adaptation) {\n        $adaptation = BuilderHelpers::normalizeNode($adaptation);\n\n        if (!$adaptation instanceof Stmt\\TraitUseAdaptation) {\n            throw new \\LogicException('Adaptation must have type TraitUseAdaptation');\n        }\n\n        $this->adaptations[] = $adaptation;\n        return $this;\n    }\n\n    /**\n     * Returns the built node.\n     *\n     * @return Node The built node\n     */\n    public function getNode(): Node {\n        return new Stmt\\TraitUse($this->traits, $this->adaptations);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/TraitUseAdaptation.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser\\Builder;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass TraitUseAdaptation implements Builder {\n    private const TYPE_UNDEFINED  = 0;\n    private const TYPE_ALIAS      = 1;\n    private const TYPE_PRECEDENCE = 2;\n\n    protected int $type;\n    protected ?Node\\Name $trait;\n    protected Node\\Identifier $method;\n    protected ?int $modifier = null;\n    protected ?Node\\Identifier $alias = null;\n    /** @var Node\\Name[] */\n    protected array $insteadof = [];\n\n    /**\n     * Creates a trait use adaptation builder.\n     *\n     * @param Node\\Name|string|null $trait Name of adapted trait\n     * @param Node\\Identifier|string $method Name of adapted method\n     */\n    public function __construct($trait, $method) {\n        $this->type = self::TYPE_UNDEFINED;\n\n        $this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait);\n        $this->method = BuilderHelpers::normalizeIdentifier($method);\n    }\n\n    /**\n     * Sets alias of method.\n     *\n     * @param Node\\Identifier|string $alias Alias for adapted method\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function as($alias) {\n        if ($this->type === self::TYPE_UNDEFINED) {\n            $this->type = self::TYPE_ALIAS;\n        }\n\n        if ($this->type !== self::TYPE_ALIAS) {\n            throw new \\LogicException('Cannot set alias for not alias adaptation buider');\n        }\n\n        $this->alias = BuilderHelpers::normalizeIdentifier($alias);\n        return $this;\n    }\n\n    /**\n     * Sets adapted method public.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePublic() {\n        $this->setModifier(Modifiers::PUBLIC);\n        return $this;\n    }\n\n    /**\n     * Sets adapted method protected.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makeProtected() {\n        $this->setModifier(Modifiers::PROTECTED);\n        return $this;\n    }\n\n    /**\n     * Sets adapted method private.\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function makePrivate() {\n        $this->setModifier(Modifiers::PRIVATE);\n        return $this;\n    }\n\n    /**\n     * Adds overwritten traits.\n     *\n     * @param Node\\Name|string ...$traits Traits for overwrite\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function insteadof(...$traits) {\n        if ($this->type === self::TYPE_UNDEFINED) {\n            if (is_null($this->trait)) {\n                throw new \\LogicException('Precedence adaptation must have trait');\n            }\n\n            $this->type = self::TYPE_PRECEDENCE;\n        }\n\n        if ($this->type !== self::TYPE_PRECEDENCE) {\n            throw new \\LogicException('Cannot add overwritten traits for not precedence adaptation buider');\n        }\n\n        foreach ($traits as $trait) {\n            $this->insteadof[] = BuilderHelpers::normalizeName($trait);\n        }\n\n        return $this;\n    }\n\n    protected function setModifier(int $modifier): void {\n        if ($this->type === self::TYPE_UNDEFINED) {\n            $this->type = self::TYPE_ALIAS;\n        }\n\n        if ($this->type !== self::TYPE_ALIAS) {\n            throw new \\LogicException('Cannot set access modifier for not alias adaptation buider');\n        }\n\n        if (is_null($this->modifier)) {\n            $this->modifier = $modifier;\n        } else {\n            throw new \\LogicException('Multiple access type modifiers are not allowed');\n        }\n    }\n\n    /**\n     * Returns the built node.\n     *\n     * @return Node The built node\n     */\n    public function getNode(): Node {\n        switch ($this->type) {\n            case self::TYPE_ALIAS:\n                return new Stmt\\TraitUseAdaptation\\Alias($this->trait, $this->method, $this->modifier, $this->alias);\n            case self::TYPE_PRECEDENCE:\n                return new Stmt\\TraitUseAdaptation\\Precedence($this->trait, $this->method, $this->insteadof);\n            default:\n                throw new \\LogicException('Type of adaptation is not defined');\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Trait_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass Trait_ extends Declaration {\n    protected string $name;\n    /** @var list<Stmt\\TraitUse> */\n    protected array $uses = [];\n    /** @var list<Stmt\\ClassConst> */\n    protected array $constants = [];\n    /** @var list<Stmt\\Property> */\n    protected array $properties = [];\n    /** @var list<Stmt\\ClassMethod> */\n    protected array $methods = [];\n    /** @var list<Node\\AttributeGroup> */\n    protected array $attributeGroups = [];\n\n    /**\n     * Creates an interface builder.\n     *\n     * @param string $name Name of the interface\n     */\n    public function __construct(string $name) {\n        $this->name = $name;\n    }\n\n    /**\n     * Adds a statement.\n     *\n     * @param Stmt|PhpParser\\Builder $stmt The statement to add\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addStmt($stmt) {\n        $stmt = BuilderHelpers::normalizeNode($stmt);\n\n        if ($stmt instanceof Stmt\\Property) {\n            $this->properties[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassMethod) {\n            $this->methods[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\TraitUse) {\n            $this->uses[] = $stmt;\n        } elseif ($stmt instanceof Stmt\\ClassConst) {\n            $this->constants[] = $stmt;\n        } else {\n            throw new \\LogicException(sprintf('Unexpected node of type \"%s\"', $stmt->getType()));\n        }\n\n        return $this;\n    }\n\n    /**\n     * Adds an attribute group.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function addAttribute($attribute) {\n        $this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);\n\n        return $this;\n    }\n\n    /**\n     * Returns the built trait node.\n     *\n     * @return Stmt\\Trait_ The built interface node\n     */\n    public function getNode(): PhpParser\\Node {\n        return new Stmt\\Trait_(\n            $this->name, [\n                'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),\n                'attrGroups' => $this->attributeGroups,\n            ], $this->attributes\n        );\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder/Use_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Builder;\n\nuse PhpParser\\Builder;\nuse PhpParser\\BuilderHelpers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Stmt;\n\nclass Use_ implements Builder {\n    protected Node\\Name $name;\n    /** @var Stmt\\Use_::TYPE_* */\n    protected int $type;\n    protected ?string $alias = null;\n\n    /**\n     * Creates a name use (alias) builder.\n     *\n     * @param Node\\Name|string $name Name of the entity (namespace, class, function, constant) to alias\n     * @param Stmt\\Use_::TYPE_* $type One of the Stmt\\Use_::TYPE_* constants\n     */\n    public function __construct($name, int $type) {\n        $this->name = BuilderHelpers::normalizeName($name);\n        $this->type = $type;\n    }\n\n    /**\n     * Sets alias for used name.\n     *\n     * @param string $alias Alias to use (last component of full name by default)\n     *\n     * @return $this The builder instance (for fluid interface)\n     */\n    public function as(string $alias) {\n        $this->alias = $alias;\n        return $this;\n    }\n\n    /**\n     * Returns the built node.\n     *\n     * @return Stmt\\Use_ The built node\n     */\n    public function getNode(): Node {\n        return new Stmt\\Use_([\n            new Node\\UseItem($this->name, $this->alias)\n        ], $this->type);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Builder.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface Builder {\n    /**\n     * Returns the built node.\n     *\n     * @return Node The built node\n     */\n    public function getNode(): Node;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/BuilderFactory.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Expr\\BinaryOp\\Concat;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Scalar\\String_;\nuse PhpParser\\Node\\Stmt\\Use_;\n\nclass BuilderFactory {\n    /**\n     * Creates an attribute node.\n     *\n     * @param string|Name $name Name of the attribute\n     * @param array $args Attribute named arguments\n     */\n    public function attribute($name, array $args = []): Node\\Attribute {\n        return new Node\\Attribute(\n            BuilderHelpers::normalizeName($name),\n            $this->args($args)\n        );\n    }\n\n    /**\n     * Creates a namespace builder.\n     *\n     * @param null|string|Node\\Name $name Name of the namespace\n     *\n     * @return Builder\\Namespace_ The created namespace builder\n     */\n    public function namespace($name): Builder\\Namespace_ {\n        return new Builder\\Namespace_($name);\n    }\n\n    /**\n     * Creates a class builder.\n     *\n     * @param string $name Name of the class\n     *\n     * @return Builder\\Class_ The created class builder\n     */\n    public function class(string $name): Builder\\Class_ {\n        return new Builder\\Class_($name);\n    }\n\n    /**\n     * Creates an interface builder.\n     *\n     * @param string $name Name of the interface\n     *\n     * @return Builder\\Interface_ The created interface builder\n     */\n    public function interface(string $name): Builder\\Interface_ {\n        return new Builder\\Interface_($name);\n    }\n\n    /**\n     * Creates a trait builder.\n     *\n     * @param string $name Name of the trait\n     *\n     * @return Builder\\Trait_ The created trait builder\n     */\n    public function trait(string $name): Builder\\Trait_ {\n        return new Builder\\Trait_($name);\n    }\n\n    /**\n     * Creates an enum builder.\n     *\n     * @param string $name Name of the enum\n     *\n     * @return Builder\\Enum_ The created enum builder\n     */\n    public function enum(string $name): Builder\\Enum_ {\n        return new Builder\\Enum_($name);\n    }\n\n    /**\n     * Creates a trait use builder.\n     *\n     * @param Node\\Name|string ...$traits Trait names\n     *\n     * @return Builder\\TraitUse The created trait use builder\n     */\n    public function useTrait(...$traits): Builder\\TraitUse {\n        return new Builder\\TraitUse(...$traits);\n    }\n\n    /**\n     * Creates a trait use adaptation builder.\n     *\n     * @param Node\\Name|string|null $trait Trait name\n     * @param Node\\Identifier|string $method Method name\n     *\n     * @return Builder\\TraitUseAdaptation The created trait use adaptation builder\n     */\n    public function traitUseAdaptation($trait, $method = null): Builder\\TraitUseAdaptation {\n        if ($method === null) {\n            $method = $trait;\n            $trait = null;\n        }\n\n        return new Builder\\TraitUseAdaptation($trait, $method);\n    }\n\n    /**\n     * Creates a method builder.\n     *\n     * @param string $name Name of the method\n     *\n     * @return Builder\\Method The created method builder\n     */\n    public function method(string $name): Builder\\Method {\n        return new Builder\\Method($name);\n    }\n\n    /**\n     * Creates a parameter builder.\n     *\n     * @param string $name Name of the parameter\n     *\n     * @return Builder\\Param The created parameter builder\n     */\n    public function param(string $name): Builder\\Param {\n        return new Builder\\Param($name);\n    }\n\n    /**\n     * Creates a property builder.\n     *\n     * @param string $name Name of the property\n     *\n     * @return Builder\\Property The created property builder\n     */\n    public function property(string $name): Builder\\Property {\n        return new Builder\\Property($name);\n    }\n\n    /**\n     * Creates a function builder.\n     *\n     * @param string $name Name of the function\n     *\n     * @return Builder\\Function_ The created function builder\n     */\n    public function function(string $name): Builder\\Function_ {\n        return new Builder\\Function_($name);\n    }\n\n    /**\n     * Creates a namespace/class use builder.\n     *\n     * @param Node\\Name|string $name Name of the entity (namespace or class) to alias\n     *\n     * @return Builder\\Use_ The created use builder\n     */\n    public function use($name): Builder\\Use_ {\n        return new Builder\\Use_($name, Use_::TYPE_NORMAL);\n    }\n\n    /**\n     * Creates a function use builder.\n     *\n     * @param Node\\Name|string $name Name of the function to alias\n     *\n     * @return Builder\\Use_ The created use function builder\n     */\n    public function useFunction($name): Builder\\Use_ {\n        return new Builder\\Use_($name, Use_::TYPE_FUNCTION);\n    }\n\n    /**\n     * Creates a constant use builder.\n     *\n     * @param Node\\Name|string $name Name of the const to alias\n     *\n     * @return Builder\\Use_ The created use const builder\n     */\n    public function useConst($name): Builder\\Use_ {\n        return new Builder\\Use_($name, Use_::TYPE_CONSTANT);\n    }\n\n    /**\n     * Creates a class constant builder.\n     *\n     * @param string|Identifier $name Name\n     * @param Node\\Expr|bool|null|int|float|string|array $value Value\n     *\n     * @return Builder\\ClassConst The created use const builder\n     */\n    public function classConst($name, $value): Builder\\ClassConst {\n        return new Builder\\ClassConst($name, $value);\n    }\n\n    /**\n     * Creates an enum case builder.\n     *\n     * @param string|Identifier $name Name\n     *\n     * @return Builder\\EnumCase The created use const builder\n     */\n    public function enumCase($name): Builder\\EnumCase {\n        return new Builder\\EnumCase($name);\n    }\n\n    /**\n     * Creates node a for a literal value.\n     *\n     * @param Expr|bool|null|int|float|string|array|\\UnitEnum $value $value\n     */\n    public function val($value): Expr {\n        return BuilderHelpers::normalizeValue($value);\n    }\n\n    /**\n     * Creates variable node.\n     *\n     * @param string|Expr $name Name\n     */\n    public function var($name): Expr\\Variable {\n        if (!\\is_string($name) && !$name instanceof Expr) {\n            throw new \\LogicException('Variable name must be string or Expr');\n        }\n\n        return new Expr\\Variable($name);\n    }\n\n    /**\n     * Normalizes an argument list.\n     *\n     * Creates Arg nodes for all arguments and converts literal values to expressions.\n     *\n     * @param array $args List of arguments to normalize\n     *\n     * @return list<Arg>\n     */\n    public function args(array $args): array {\n        $normalizedArgs = [];\n        foreach ($args as $key => $arg) {\n            if (!($arg instanceof Arg)) {\n                $arg = new Arg(BuilderHelpers::normalizeValue($arg));\n            }\n            if (\\is_string($key)) {\n                $arg->name = BuilderHelpers::normalizeIdentifier($key);\n            }\n            $normalizedArgs[] = $arg;\n        }\n        return $normalizedArgs;\n    }\n\n    /**\n     * Creates a function call node.\n     *\n     * @param string|Name|Expr $name Function name\n     * @param array $args Function arguments\n     */\n    public function funcCall($name, array $args = []): Expr\\FuncCall {\n        return new Expr\\FuncCall(\n            BuilderHelpers::normalizeNameOrExpr($name),\n            $this->args($args)\n        );\n    }\n\n    /**\n     * Creates a method call node.\n     *\n     * @param Expr $var Variable the method is called on\n     * @param string|Identifier|Expr $name Method name\n     * @param array $args Method arguments\n     */\n    public function methodCall(Expr $var, $name, array $args = []): Expr\\MethodCall {\n        return new Expr\\MethodCall(\n            $var,\n            BuilderHelpers::normalizeIdentifierOrExpr($name),\n            $this->args($args)\n        );\n    }\n\n    /**\n     * Creates a static method call node.\n     *\n     * @param string|Name|Expr $class Class name\n     * @param string|Identifier|Expr $name Method name\n     * @param array $args Method arguments\n     */\n    public function staticCall($class, $name, array $args = []): Expr\\StaticCall {\n        return new Expr\\StaticCall(\n            BuilderHelpers::normalizeNameOrExpr($class),\n            BuilderHelpers::normalizeIdentifierOrExpr($name),\n            $this->args($args)\n        );\n    }\n\n    /**\n     * Creates an object creation node.\n     *\n     * @param string|Name|Expr $class Class name\n     * @param array $args Constructor arguments\n     */\n    public function new($class, array $args = []): Expr\\New_ {\n        return new Expr\\New_(\n            BuilderHelpers::normalizeNameOrExpr($class),\n            $this->args($args)\n        );\n    }\n\n    /**\n     * Creates a constant fetch node.\n     *\n     * @param string|Name $name Constant name\n     */\n    public function constFetch($name): Expr\\ConstFetch {\n        return new Expr\\ConstFetch(BuilderHelpers::normalizeName($name));\n    }\n\n    /**\n     * Creates a property fetch node.\n     *\n     * @param Expr $var Variable holding object\n     * @param string|Identifier|Expr $name Property name\n     */\n    public function propertyFetch(Expr $var, $name): Expr\\PropertyFetch {\n        return new Expr\\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name));\n    }\n\n    /**\n     * Creates a class constant fetch node.\n     *\n     * @param string|Name|Expr $class Class name\n     * @param string|Identifier|Expr $name Constant name\n     */\n    public function classConstFetch($class, $name): Expr\\ClassConstFetch {\n        return new Expr\\ClassConstFetch(\n            BuilderHelpers::normalizeNameOrExpr($class),\n            BuilderHelpers::normalizeIdentifierOrExpr($name)\n        );\n    }\n\n    /**\n     * Creates nested Concat nodes from a list of expressions.\n     *\n     * @param Expr|string ...$exprs Expressions or literal strings\n     */\n    public function concat(...$exprs): Concat {\n        $numExprs = count($exprs);\n        if ($numExprs < 2) {\n            throw new \\LogicException('Expected at least two expressions');\n        }\n\n        $lastConcat = $this->normalizeStringExpr($exprs[0]);\n        for ($i = 1; $i < $numExprs; $i++) {\n            $lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i]));\n        }\n        return $lastConcat;\n    }\n\n    /**\n     * @param string|Expr $expr\n     */\n    private function normalizeStringExpr($expr): Expr {\n        if ($expr instanceof Expr) {\n            return $expr;\n        }\n\n        if (\\is_string($expr)) {\n            return new String_($expr);\n        }\n\n        throw new \\LogicException('Expected string or Expr');\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/BuilderHelpers.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\ComplexType;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Name\\FullyQualified;\nuse PhpParser\\Node\\NullableType;\nuse PhpParser\\Node\\Scalar;\nuse PhpParser\\Node\\Stmt;\n\n/**\n * This class defines helpers used in the implementation of builders. Don't use it directly.\n *\n * @internal\n */\nfinal class BuilderHelpers {\n    /**\n     * Normalizes a node: Converts builder objects to nodes.\n     *\n     * @param Node|Builder $node The node to normalize\n     *\n     * @return Node The normalized node\n     */\n    public static function normalizeNode($node): Node {\n        if ($node instanceof Builder) {\n            return $node->getNode();\n        }\n\n        if ($node instanceof Node) {\n            return $node;\n        }\n\n        throw new \\LogicException('Expected node or builder object');\n    }\n\n    /**\n     * Normalizes a node to a statement.\n     *\n     * Expressions are wrapped in a Stmt\\Expression node.\n     *\n     * @param Node|Builder $node The node to normalize\n     *\n     * @return Stmt The normalized statement node\n     */\n    public static function normalizeStmt($node): Stmt {\n        $node = self::normalizeNode($node);\n        if ($node instanceof Stmt) {\n            return $node;\n        }\n\n        if ($node instanceof Expr) {\n            return new Stmt\\Expression($node);\n        }\n\n        throw new \\LogicException('Expected statement or expression node');\n    }\n\n    /**\n     * Normalizes strings to Identifier.\n     *\n     * @param string|Identifier $name The identifier to normalize\n     *\n     * @return Identifier The normalized identifier\n     */\n    public static function normalizeIdentifier($name): Identifier {\n        if ($name instanceof Identifier) {\n            return $name;\n        }\n\n        if (\\is_string($name)) {\n            return new Identifier($name);\n        }\n\n        throw new \\LogicException('Expected string or instance of Node\\Identifier');\n    }\n\n    /**\n     * Normalizes strings to Identifier, also allowing expressions.\n     *\n     * @param string|Identifier|Expr $name The identifier to normalize\n     *\n     * @return Identifier|Expr The normalized identifier or expression\n     */\n    public static function normalizeIdentifierOrExpr($name) {\n        if ($name instanceof Identifier || $name instanceof Expr) {\n            return $name;\n        }\n\n        if (\\is_string($name)) {\n            return new Identifier($name);\n        }\n\n        throw new \\LogicException('Expected string or instance of Node\\Identifier or Node\\Expr');\n    }\n\n    /**\n     * Normalizes a name: Converts string names to Name nodes.\n     *\n     * @param Name|string $name The name to normalize\n     *\n     * @return Name The normalized name\n     */\n    public static function normalizeName($name): Name {\n        if ($name instanceof Name) {\n            return $name;\n        }\n\n        if (is_string($name)) {\n            if (!$name) {\n                throw new \\LogicException('Name cannot be empty');\n            }\n\n            if ($name[0] === '\\\\') {\n                return new Name\\FullyQualified(substr($name, 1));\n            }\n\n            if (0 === strpos($name, 'namespace\\\\')) {\n                return new Name\\Relative(substr($name, strlen('namespace\\\\')));\n            }\n\n            return new Name($name);\n        }\n\n        throw new \\LogicException('Name must be a string or an instance of Node\\Name');\n    }\n\n    /**\n     * Normalizes a name: Converts string names to Name nodes, while also allowing expressions.\n     *\n     * @param Expr|Name|string $name The name to normalize\n     *\n     * @return Name|Expr The normalized name or expression\n     */\n    public static function normalizeNameOrExpr($name) {\n        if ($name instanceof Expr) {\n            return $name;\n        }\n\n        if (!is_string($name) && !($name instanceof Name)) {\n            throw new \\LogicException(\n                'Name must be a string or an instance of Node\\Name or Node\\Expr'\n            );\n        }\n\n        return self::normalizeName($name);\n    }\n\n    /**\n     * Normalizes a type: Converts plain-text type names into proper AST representation.\n     *\n     * In particular, builtin types become Identifiers, custom types become Names and nullables\n     * are wrapped in NullableType nodes.\n     *\n     * @param string|Name|Identifier|ComplexType $type The type to normalize\n     *\n     * @return Name|Identifier|ComplexType The normalized type\n     */\n    public static function normalizeType($type) {\n        if (!is_string($type)) {\n            if (\n                !$type instanceof Name && !$type instanceof Identifier &&\n                !$type instanceof ComplexType\n            ) {\n                throw new \\LogicException(\n                    'Type must be a string, or an instance of Name, Identifier or ComplexType'\n                );\n            }\n            return $type;\n        }\n\n        $nullable = false;\n        if (strlen($type) > 0 && $type[0] === '?') {\n            $nullable = true;\n            $type = substr($type, 1);\n        }\n\n        $builtinTypes = [\n            'array',\n            'callable',\n            'bool',\n            'int',\n            'float',\n            'string',\n            'iterable',\n            'void',\n            'object',\n            'null',\n            'false',\n            'mixed',\n            'never',\n            'true',\n        ];\n\n        $lowerType = strtolower($type);\n        if (in_array($lowerType, $builtinTypes)) {\n            $type = new Identifier($lowerType);\n        } else {\n            $type = self::normalizeName($type);\n        }\n\n        $notNullableTypes = [\n            'void', 'mixed', 'never',\n        ];\n        if ($nullable && in_array((string) $type, $notNullableTypes)) {\n            throw new \\LogicException(sprintf('%s type cannot be nullable', $type));\n        }\n\n        return $nullable ? new NullableType($type) : $type;\n    }\n\n    /**\n     * Normalizes a value: Converts nulls, booleans, integers,\n     * floats, strings and arrays into their respective nodes\n     *\n     * @param Node\\Expr|bool|null|int|float|string|array|\\UnitEnum $value The value to normalize\n     *\n     * @return Expr The normalized value\n     */\n    public static function normalizeValue($value): Expr {\n        if ($value instanceof Node\\Expr) {\n            return $value;\n        }\n\n        if (is_null($value)) {\n            return new Expr\\ConstFetch(\n                new Name('null')\n            );\n        }\n\n        if (is_bool($value)) {\n            return new Expr\\ConstFetch(\n                new Name($value ? 'true' : 'false')\n            );\n        }\n\n        if (is_int($value)) {\n            return new Scalar\\Int_($value);\n        }\n\n        if (is_float($value)) {\n            return new Scalar\\Float_($value);\n        }\n\n        if (is_string($value)) {\n            return new Scalar\\String_($value);\n        }\n\n        if (is_array($value)) {\n            $items = [];\n            $lastKey = -1;\n            foreach ($value as $itemKey => $itemValue) {\n                // for consecutive, numeric keys don't generate keys\n                if (null !== $lastKey && ++$lastKey === $itemKey) {\n                    $items[] = new Node\\ArrayItem(\n                        self::normalizeValue($itemValue)\n                    );\n                } else {\n                    $lastKey = null;\n                    $items[] = new Node\\ArrayItem(\n                        self::normalizeValue($itemValue),\n                        self::normalizeValue($itemKey)\n                    );\n                }\n            }\n\n            return new Expr\\Array_($items);\n        }\n\n        if ($value instanceof \\UnitEnum) {\n            return new Expr\\ClassConstFetch(new FullyQualified(\\get_class($value)), new Identifier($value->name));\n        }\n\n        throw new \\LogicException('Invalid value');\n    }\n\n    /**\n     * Normalizes a doc comment: Converts plain strings to PhpParser\\Comment\\Doc.\n     *\n     * @param Comment\\Doc|string $docComment The doc comment to normalize\n     *\n     * @return Comment\\Doc The normalized doc comment\n     */\n    public static function normalizeDocComment($docComment): Comment\\Doc {\n        if ($docComment instanceof Comment\\Doc) {\n            return $docComment;\n        }\n\n        if (is_string($docComment)) {\n            return new Comment\\Doc($docComment);\n        }\n\n        throw new \\LogicException('Doc comment must be a string or an instance of PhpParser\\Comment\\Doc');\n    }\n\n    /**\n     * Normalizes a attribute: Converts attribute to the Attribute Group if needed.\n     *\n     * @param Node\\Attribute|Node\\AttributeGroup $attribute\n     *\n     * @return Node\\AttributeGroup The Attribute Group\n     */\n    public static function normalizeAttribute($attribute): Node\\AttributeGroup {\n        if ($attribute instanceof Node\\AttributeGroup) {\n            return $attribute;\n        }\n\n        if (!($attribute instanceof Node\\Attribute)) {\n            throw new \\LogicException('Attribute must be an instance of PhpParser\\Node\\Attribute or PhpParser\\Node\\AttributeGroup');\n        }\n\n        return new Node\\AttributeGroup([$attribute]);\n    }\n\n    /**\n     * Adds a modifier and returns new modifier bitmask.\n     *\n     * @param int $modifiers Existing modifiers\n     * @param int $modifier Modifier to set\n     *\n     * @return int New modifiers\n     */\n    public static function addModifier(int $modifiers, int $modifier): int {\n        Modifiers::verifyModifier($modifiers, $modifier);\n        return $modifiers | $modifier;\n    }\n\n    /**\n     * Adds a modifier and returns new modifier bitmask.\n     * @return int New modifiers\n     */\n    public static function addClassModifier(int $existingModifiers, int $modifierToSet): int {\n        Modifiers::verifyClassModifier($existingModifiers, $modifierToSet);\n        return $existingModifiers | $modifierToSet;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Comment/Doc.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Comment;\n\nclass Doc extends \\PhpParser\\Comment {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Comment.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nclass Comment implements \\JsonSerializable {\n    protected string $text;\n    protected int $startLine;\n    protected int $startFilePos;\n    protected int $startTokenPos;\n    protected int $endLine;\n    protected int $endFilePos;\n    protected int $endTokenPos;\n\n    /**\n     * Constructs a comment node.\n     *\n     * @param string $text Comment text (including comment delimiters like /*)\n     * @param int $startLine Line number the comment started on\n     * @param int $startFilePos File offset the comment started on\n     * @param int $startTokenPos Token offset the comment started on\n     */\n    public function __construct(\n        string $text,\n        int $startLine = -1, int $startFilePos = -1, int $startTokenPos = -1,\n        int $endLine = -1, int $endFilePos = -1, int $endTokenPos = -1\n    ) {\n        $this->text = $text;\n        $this->startLine = $startLine;\n        $this->startFilePos = $startFilePos;\n        $this->startTokenPos = $startTokenPos;\n        $this->endLine = $endLine;\n        $this->endFilePos = $endFilePos;\n        $this->endTokenPos = $endTokenPos;\n    }\n\n    /**\n     * Gets the comment text.\n     *\n     * @return string The comment text (including comment delimiters like /*)\n     */\n    public function getText(): string {\n        return $this->text;\n    }\n\n    /**\n     * Gets the line number the comment started on.\n     *\n     * @return int Line number (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getStartLine(): int {\n        return $this->startLine;\n    }\n\n    /**\n     * Gets the file offset the comment started on.\n     *\n     * @return int File offset (or -1 if not available)\n     */\n    public function getStartFilePos(): int {\n        return $this->startFilePos;\n    }\n\n    /**\n     * Gets the token offset the comment started on.\n     *\n     * @return int Token offset (or -1 if not available)\n     */\n    public function getStartTokenPos(): int {\n        return $this->startTokenPos;\n    }\n\n    /**\n     * Gets the line number the comment ends on.\n     *\n     * @return int Line number (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getEndLine(): int {\n        return $this->endLine;\n    }\n\n    /**\n     * Gets the file offset the comment ends on.\n     *\n     * @return int File offset (or -1 if not available)\n     */\n    public function getEndFilePos(): int {\n        return $this->endFilePos;\n    }\n\n    /**\n     * Gets the token offset the comment ends on.\n     *\n     * @return int Token offset (or -1 if not available)\n     */\n    public function getEndTokenPos(): int {\n        return $this->endTokenPos;\n    }\n\n    /**\n     * Gets the comment text.\n     *\n     * @return string The comment text (including comment delimiters like /*)\n     */\n    public function __toString(): string {\n        return $this->text;\n    }\n\n    /**\n     * Gets the reformatted comment text.\n     *\n     * \"Reformatted\" here means that we try to clean up the whitespace at the\n     * starts of the lines. This is necessary because we receive the comments\n     * without leading whitespace on the first line, but with leading whitespace\n     * on all subsequent lines.\n     *\n     * Additionally, this normalizes CRLF newlines to LF newlines.\n     */\n    public function getReformattedText(): string {\n        $text = str_replace(\"\\r\\n\", \"\\n\", $this->text);\n        $newlinePos = strpos($text, \"\\n\");\n        if (false === $newlinePos) {\n            // Single line comments don't need further processing\n            return $text;\n        }\n        if (preg_match('(^.*(?:\\n\\s+\\*.*)+$)', $text)) {\n            // Multi line comment of the type\n            //\n            //     /*\n            //      * Some text.\n            //      * Some more text.\n            //      */\n            //\n            // is handled by replacing the whitespace sequences before the * by a single space\n            return preg_replace('(^\\s+\\*)m', ' *', $text);\n        }\n        if (preg_match('(^/\\*\\*?\\s*\\n)', $text) && preg_match('(\\n(\\s*)\\*/$)', $text, $matches)) {\n            // Multi line comment of the type\n            //\n            //    /*\n            //        Some text.\n            //        Some more text.\n            //    */\n            //\n            // is handled by removing the whitespace sequence on the line before the closing\n            // */ on all lines. So if the last line is \"    */\", then \"    \" is removed at the\n            // start of all lines.\n            return preg_replace('(^' . preg_quote($matches[1]) . ')m', '', $text);\n        }\n        if (preg_match('(^/\\*\\*?\\s*(?!\\s))', $text, $matches)) {\n            // Multi line comment of the type\n            //\n            //     /* Some text.\n            //        Some more text.\n            //          Indented text.\n            //        Even more text. */\n            //\n            // is handled by removing the difference between the shortest whitespace prefix on all\n            // lines and the length of the \"/* \" opening sequence.\n            $prefixLen = $this->getShortestWhitespacePrefixLen(substr($text, $newlinePos + 1));\n            $removeLen = $prefixLen - strlen($matches[0]);\n            return preg_replace('(^\\s{' . $removeLen . '})m', '', $text);\n        }\n\n        // No idea how to format this comment, so simply return as is\n        return $text;\n    }\n\n    /**\n     * Get length of shortest whitespace prefix (at the start of a line).\n     *\n     * If there is a line with no prefix whitespace, 0 is a valid return value.\n     *\n     * @param string $str String to check\n     * @return int Length in characters. Tabs count as single characters.\n     */\n    private function getShortestWhitespacePrefixLen(string $str): int {\n        $lines = explode(\"\\n\", $str);\n        $shortestPrefixLen = \\PHP_INT_MAX;\n        foreach ($lines as $line) {\n            preg_match('(^\\s*)', $line, $matches);\n            $prefixLen = strlen($matches[0]);\n            if ($prefixLen < $shortestPrefixLen) {\n                $shortestPrefixLen = $prefixLen;\n            }\n        }\n        return $shortestPrefixLen;\n    }\n\n    /**\n     * @return array{nodeType:string, text:mixed, line:mixed, filePos:mixed}\n     */\n    public function jsonSerialize(): array {\n        // Technically not a node, but we make it look like one anyway\n        $type = $this instanceof Comment\\Doc ? 'Comment_Doc' : 'Comment';\n        return [\n            'nodeType' => $type,\n            'text' => $this->text,\n            // TODO: Rename these to include \"start\".\n            'line' => $this->startLine,\n            'filePos' => $this->startFilePos,\n            'tokenPos' => $this->startTokenPos,\n            'endLine' => $this->endLine,\n            'endFilePos' => $this->endFilePos,\n            'endTokenPos' => $this->endTokenPos,\n        ];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluationException.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nclass ConstExprEvaluationException extends \\Exception {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ConstExprEvaluator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Scalar;\n\nuse function array_merge;\n\n/**\n * Evaluates constant expressions.\n *\n * This evaluator is able to evaluate all constant expressions (as defined by PHP), which can be\n * evaluated without further context. If a subexpression is not of this type, a user-provided\n * fallback evaluator is invoked. To support all constant expressions that are also supported by\n * PHP (and not already handled by this class), the fallback evaluator must be able to handle the\n * following node types:\n *\n *  * All Scalar\\MagicConst\\* nodes.\n *  * Expr\\ConstFetch nodes. Only null/false/true are already handled by this class.\n *  * Expr\\ClassConstFetch nodes.\n *\n * The fallback evaluator should throw ConstExprEvaluationException for nodes it cannot evaluate.\n *\n * The evaluation is dependent on runtime configuration in two respects: Firstly, floating\n * point to string conversions are affected by the precision ini setting. Secondly, they are also\n * affected by the LC_NUMERIC locale.\n */\nclass ConstExprEvaluator {\n    /** @var callable|null */\n    private $fallbackEvaluator;\n\n    /**\n     * Create a constant expression evaluator.\n     *\n     * The provided fallback evaluator is invoked whenever a subexpression cannot be evaluated. See\n     * class doc comment for more information.\n     *\n     * @param callable|null $fallbackEvaluator To call if subexpression cannot be evaluated\n     */\n    public function __construct(?callable $fallbackEvaluator = null) {\n        $this->fallbackEvaluator = $fallbackEvaluator ?? function (Expr $expr) {\n            throw new ConstExprEvaluationException(\n                \"Expression of type {$expr->getType()} cannot be evaluated\"\n            );\n        };\n    }\n\n    /**\n     * Silently evaluates a constant expression into a PHP value.\n     *\n     * Thrown Errors, warnings or notices will be converted into a ConstExprEvaluationException.\n     * The original source of the exception is available through getPrevious().\n     *\n     * If some part of the expression cannot be evaluated, the fallback evaluator passed to the\n     * constructor will be invoked. By default, if no fallback is provided, an exception of type\n     * ConstExprEvaluationException is thrown.\n     *\n     * See class doc comment for caveats and limitations.\n     *\n     * @param Expr $expr Constant expression to evaluate\n     * @return mixed Result of evaluation\n     *\n     * @throws ConstExprEvaluationException if the expression cannot be evaluated or an error occurred\n     */\n    public function evaluateSilently(Expr $expr) {\n        set_error_handler(function ($num, $str, $file, $line) {\n            throw new \\ErrorException($str, 0, $num, $file, $line);\n        });\n\n        try {\n            return $this->evaluate($expr);\n        } catch (\\Throwable $e) {\n            if (!$e instanceof ConstExprEvaluationException) {\n                $e = new ConstExprEvaluationException(\n                    \"An error occurred during constant expression evaluation\", 0, $e);\n            }\n            throw $e;\n        } finally {\n            restore_error_handler();\n        }\n    }\n\n    /**\n     * Directly evaluates a constant expression into a PHP value.\n     *\n     * May generate Error exceptions, warnings or notices. Use evaluateSilently() to convert these\n     * into a ConstExprEvaluationException.\n     *\n     * If some part of the expression cannot be evaluated, the fallback evaluator passed to the\n     * constructor will be invoked. By default, if no fallback is provided, an exception of type\n     * ConstExprEvaluationException is thrown.\n     *\n     * See class doc comment for caveats and limitations.\n     *\n     * @param Expr $expr Constant expression to evaluate\n     * @return mixed Result of evaluation\n     *\n     * @throws ConstExprEvaluationException if the expression cannot be evaluated\n     */\n    public function evaluateDirectly(Expr $expr) {\n        return $this->evaluate($expr);\n    }\n\n    /** @return mixed */\n    private function evaluate(Expr $expr) {\n        if ($expr instanceof Scalar\\Int_\n            || $expr instanceof Scalar\\Float_\n            || $expr instanceof Scalar\\String_\n        ) {\n            return $expr->value;\n        }\n\n        if ($expr instanceof Expr\\Array_) {\n            return $this->evaluateArray($expr);\n        }\n\n        // Unary operators\n        if ($expr instanceof Expr\\UnaryPlus) {\n            return +$this->evaluate($expr->expr);\n        }\n        if ($expr instanceof Expr\\UnaryMinus) {\n            return -$this->evaluate($expr->expr);\n        }\n        if ($expr instanceof Expr\\BooleanNot) {\n            return !$this->evaluate($expr->expr);\n        }\n        if ($expr instanceof Expr\\BitwiseNot) {\n            return ~$this->evaluate($expr->expr);\n        }\n\n        if ($expr instanceof Expr\\BinaryOp) {\n            return $this->evaluateBinaryOp($expr);\n        }\n\n        if ($expr instanceof Expr\\Ternary) {\n            return $this->evaluateTernary($expr);\n        }\n\n        if ($expr instanceof Expr\\ArrayDimFetch && null !== $expr->dim) {\n            return $this->evaluate($expr->var)[$this->evaluate($expr->dim)];\n        }\n\n        if ($expr instanceof Expr\\ConstFetch) {\n            return $this->evaluateConstFetch($expr);\n        }\n\n        return ($this->fallbackEvaluator)($expr);\n    }\n\n    private function evaluateArray(Expr\\Array_ $expr): array {\n        $array = [];\n        foreach ($expr->items as $item) {\n            if (null !== $item->key) {\n                $array[$this->evaluate($item->key)] = $this->evaluate($item->value);\n            } elseif ($item->unpack) {\n                $array = array_merge($array, $this->evaluate($item->value));\n            } else {\n                $array[] = $this->evaluate($item->value);\n            }\n        }\n        return $array;\n    }\n\n    /** @return mixed */\n    private function evaluateTernary(Expr\\Ternary $expr) {\n        if (null === $expr->if) {\n            return $this->evaluate($expr->cond) ?: $this->evaluate($expr->else);\n        }\n\n        return $this->evaluate($expr->cond)\n            ? $this->evaluate($expr->if)\n            : $this->evaluate($expr->else);\n    }\n\n    /** @return mixed */\n    private function evaluateBinaryOp(Expr\\BinaryOp $expr) {\n        if ($expr instanceof Expr\\BinaryOp\\Coalesce\n            && $expr->left instanceof Expr\\ArrayDimFetch\n        ) {\n            // This needs to be special cased to respect BP_VAR_IS fetch semantics\n            return $this->evaluate($expr->left->var)[$this->evaluate($expr->left->dim)]\n                ?? $this->evaluate($expr->right);\n        }\n\n        // The evaluate() calls are repeated in each branch, because some of the operators are\n        // short-circuiting and evaluating the RHS in advance may be illegal in that case\n        $l = $expr->left;\n        $r = $expr->right;\n        switch ($expr->getOperatorSigil()) {\n            case '&':   return $this->evaluate($l) &   $this->evaluate($r);\n            case '|':   return $this->evaluate($l) |   $this->evaluate($r);\n            case '^':   return $this->evaluate($l) ^   $this->evaluate($r);\n            case '&&':  return $this->evaluate($l) &&  $this->evaluate($r);\n            case '||':  return $this->evaluate($l) ||  $this->evaluate($r);\n            case '??':  return $this->evaluate($l) ??  $this->evaluate($r);\n            case '.':   return $this->evaluate($l) .   $this->evaluate($r);\n            case '/':   return $this->evaluate($l) /   $this->evaluate($r);\n            case '==':  return $this->evaluate($l) ==  $this->evaluate($r);\n            case '>':   return $this->evaluate($l) >   $this->evaluate($r);\n            case '>=':  return $this->evaluate($l) >=  $this->evaluate($r);\n            case '===': return $this->evaluate($l) === $this->evaluate($r);\n            case 'and': return $this->evaluate($l) and $this->evaluate($r);\n            case 'or':  return $this->evaluate($l) or  $this->evaluate($r);\n            case 'xor': return $this->evaluate($l) xor $this->evaluate($r);\n            case '-':   return $this->evaluate($l) -   $this->evaluate($r);\n            case '%':   return $this->evaluate($l) %   $this->evaluate($r);\n            case '*':   return $this->evaluate($l) *   $this->evaluate($r);\n            case '!=':  return $this->evaluate($l) !=  $this->evaluate($r);\n            case '!==': return $this->evaluate($l) !== $this->evaluate($r);\n            case '+':   return $this->evaluate($l) +   $this->evaluate($r);\n            case '**':  return $this->evaluate($l) **  $this->evaluate($r);\n            case '<<':  return $this->evaluate($l) <<  $this->evaluate($r);\n            case '>>':  return $this->evaluate($l) >>  $this->evaluate($r);\n            case '<':   return $this->evaluate($l) <   $this->evaluate($r);\n            case '<=':  return $this->evaluate($l) <=  $this->evaluate($r);\n            case '<=>': return $this->evaluate($l) <=> $this->evaluate($r);\n            case '|>':  return ($this->fallbackEvaluator)($expr);\n        }\n\n        throw new \\Exception('Should not happen');\n    }\n\n    /** @return mixed */\n    private function evaluateConstFetch(Expr\\ConstFetch $expr) {\n        $name = $expr->name->toLowerString();\n        switch ($name) {\n            case 'null': return null;\n            case 'false': return false;\n            case 'true': return true;\n        }\n\n        return ($this->fallbackEvaluator)($expr);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Error.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nclass Error extends \\RuntimeException {\n    protected string $rawMessage;\n    /** @var array<string, mixed> */\n    protected array $attributes;\n\n    /**\n     * Creates an Exception signifying a parse error.\n     *\n     * @param string $message Error message\n     * @param array<string, mixed> $attributes Attributes of node/token where error occurred\n     */\n    public function __construct(string $message, array $attributes = []) {\n        $this->rawMessage = $message;\n        $this->attributes = $attributes;\n        $this->updateMessage();\n    }\n\n    /**\n     * Gets the error message\n     *\n     * @return string Error message\n     */\n    public function getRawMessage(): string {\n        return $this->rawMessage;\n    }\n\n    /**\n     * Gets the line the error starts in.\n     *\n     * @return int Error start line\n     * @phpstan-return -1|positive-int\n     */\n    public function getStartLine(): int {\n        return $this->attributes['startLine'] ?? -1;\n    }\n\n    /**\n     * Gets the line the error ends in.\n     *\n     * @return int Error end line\n     * @phpstan-return -1|positive-int\n     */\n    public function getEndLine(): int {\n        return $this->attributes['endLine'] ?? -1;\n    }\n\n    /**\n     * Gets the attributes of the node/token the error occurred at.\n     *\n     * @return array<string, mixed>\n     */\n    public function getAttributes(): array {\n        return $this->attributes;\n    }\n\n    /**\n     * Sets the attributes of the node/token the error occurred at.\n     *\n     * @param array<string, mixed> $attributes\n     */\n    public function setAttributes(array $attributes): void {\n        $this->attributes = $attributes;\n        $this->updateMessage();\n    }\n\n    /**\n     * Sets the line of the PHP file the error occurred in.\n     *\n     * @param string $message Error message\n     */\n    public function setRawMessage(string $message): void {\n        $this->rawMessage = $message;\n        $this->updateMessage();\n    }\n\n    /**\n     * Sets the line the error starts in.\n     *\n     * @param int $line Error start line\n     */\n    public function setStartLine(int $line): void {\n        $this->attributes['startLine'] = $line;\n        $this->updateMessage();\n    }\n\n    /**\n     * Returns whether the error has start and end column information.\n     *\n     * For column information enable the startFilePos and endFilePos in the lexer options.\n     */\n    public function hasColumnInfo(): bool {\n        return isset($this->attributes['startFilePos'], $this->attributes['endFilePos']);\n    }\n\n    /**\n     * Gets the start column (1-based) into the line where the error started.\n     *\n     * @param string $code Source code of the file\n     */\n    public function getStartColumn(string $code): int {\n        if (!$this->hasColumnInfo()) {\n            throw new \\RuntimeException('Error does not have column information');\n        }\n\n        return $this->toColumn($code, $this->attributes['startFilePos']);\n    }\n\n    /**\n     * Gets the end column (1-based) into the line where the error ended.\n     *\n     * @param string $code Source code of the file\n     */\n    public function getEndColumn(string $code): int {\n        if (!$this->hasColumnInfo()) {\n            throw new \\RuntimeException('Error does not have column information');\n        }\n\n        return $this->toColumn($code, $this->attributes['endFilePos']);\n    }\n\n    /**\n     * Formats message including line and column information.\n     *\n     * @param string $code Source code associated with the error, for calculation of the columns\n     *\n     * @return string Formatted message\n     */\n    public function getMessageWithColumnInfo(string $code): string {\n        return sprintf(\n            '%s from %d:%d to %d:%d', $this->getRawMessage(),\n            $this->getStartLine(), $this->getStartColumn($code),\n            $this->getEndLine(), $this->getEndColumn($code)\n        );\n    }\n\n    /**\n     * Converts a file offset into a column.\n     *\n     * @param string $code Source code that $pos indexes into\n     * @param int $pos 0-based position in $code\n     *\n     * @return int 1-based column (relative to start of line)\n     */\n    private function toColumn(string $code, int $pos): int {\n        if ($pos > strlen($code)) {\n            throw new \\RuntimeException('Invalid position information');\n        }\n\n        $lineStartPos = strrpos($code, \"\\n\", $pos - strlen($code));\n        if (false === $lineStartPos) {\n            $lineStartPos = -1;\n        }\n\n        return $pos - $lineStartPos;\n    }\n\n    /**\n     * Updates the exception message after a change to rawMessage or rawLine.\n     */\n    protected function updateMessage(): void {\n        $this->message = $this->rawMessage;\n\n        if (-1 === $this->getStartLine()) {\n            $this->message .= ' on unknown line';\n        } else {\n            $this->message .= ' on line ' . $this->getStartLine();\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Collecting.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\ErrorHandler;\n\nuse PhpParser\\Error;\nuse PhpParser\\ErrorHandler;\n\n/**\n * Error handler that collects all errors into an array.\n *\n * This allows graceful handling of errors.\n */\nclass Collecting implements ErrorHandler {\n    /** @var Error[] Collected errors */\n    private array $errors = [];\n\n    public function handleError(Error $error): void {\n        $this->errors[] = $error;\n    }\n\n    /**\n     * Get collected errors.\n     *\n     * @return Error[]\n     */\n    public function getErrors(): array {\n        return $this->errors;\n    }\n\n    /**\n     * Check whether there are any errors.\n     */\n    public function hasErrors(): bool {\n        return !empty($this->errors);\n    }\n\n    /**\n     * Reset/clear collected errors.\n     */\n    public function clearErrors(): void {\n        $this->errors = [];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler/Throwing.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\ErrorHandler;\n\nuse PhpParser\\Error;\nuse PhpParser\\ErrorHandler;\n\n/**\n * Error handler that handles all errors by throwing them.\n *\n * This is the default strategy used by all components.\n */\nclass Throwing implements ErrorHandler {\n    public function handleError(Error $error): void {\n        throw $error;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ErrorHandler.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface ErrorHandler {\n    /**\n     * Handle an error generated during lexing, parsing or some other operation.\n     *\n     * @param Error $error The error that needs to be handled\n     */\n    public function handleError(Error $error): void;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal/DiffElem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Internal;\n\n/**\n * @internal\n */\nclass DiffElem {\n    public const TYPE_KEEP = 0;\n    public const TYPE_REMOVE = 1;\n    public const TYPE_ADD = 2;\n    public const TYPE_REPLACE = 3;\n\n    /** @var int One of the TYPE_* constants */\n    public int $type;\n    /** @var mixed Is null for add operations */\n    public $old;\n    /** @var mixed Is null for remove operations */\n    public $new;\n\n    /**\n     * @param int $type One of the TYPE_* constants\n     * @param mixed $old Is null for add operations\n     * @param mixed $new Is null for remove operations\n     */\n    public function __construct(int $type, $old, $new) {\n        $this->type = $type;\n        $this->old = $old;\n        $this->new = $new;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal/Differ.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Internal;\n\n/**\n * Implements the Myers diff algorithm.\n *\n * Myers, Eugene W. \"An O (ND) difference algorithm and its variations.\"\n * Algorithmica 1.1 (1986): 251-266.\n *\n * @template T\n * @internal\n */\nclass Differ {\n    /** @var callable(T, T): bool */\n    private $isEqual;\n\n    /**\n     * Create differ over the given equality relation.\n     *\n     * @param callable(T, T): bool $isEqual Equality relation\n     */\n    public function __construct(callable $isEqual) {\n        $this->isEqual = $isEqual;\n    }\n\n    /**\n     * Calculate diff (edit script) from $old to $new.\n     *\n     * @param T[] $old Original array\n     * @param T[] $new New array\n     *\n     * @return DiffElem[] Diff (edit script)\n     */\n    public function diff(array $old, array $new): array {\n        $old = \\array_values($old);\n        $new = \\array_values($new);\n        list($trace, $x, $y) = $this->calculateTrace($old, $new);\n        return $this->extractDiff($trace, $x, $y, $old, $new);\n    }\n\n    /**\n     * Calculate diff, including \"replace\" operations.\n     *\n     * If a sequence of remove operations is followed by the same number of add operations, these\n     * will be coalesced into replace operations.\n     *\n     * @param T[] $old Original array\n     * @param T[] $new New array\n     *\n     * @return DiffElem[] Diff (edit script), including replace operations\n     */\n    public function diffWithReplacements(array $old, array $new): array {\n        return $this->coalesceReplacements($this->diff($old, $new));\n    }\n\n    /**\n     * @param T[] $old\n     * @param T[] $new\n     * @return array{array<int, array<int, int>>, int, int}\n     */\n    private function calculateTrace(array $old, array $new): array {\n        $n = \\count($old);\n        $m = \\count($new);\n        $max = $n + $m;\n        $v = [1 => 0];\n        $trace = [];\n        for ($d = 0; $d <= $max; $d++) {\n            $trace[] = $v;\n            for ($k = -$d; $k <= $d; $k += 2) {\n                if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {\n                    $x = $v[$k + 1];\n                } else {\n                    $x = $v[$k - 1] + 1;\n                }\n\n                $y = $x - $k;\n                while ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) {\n                    $x++;\n                    $y++;\n                }\n\n                $v[$k] = $x;\n                if ($x >= $n && $y >= $m) {\n                    return [$trace, $x, $y];\n                }\n            }\n        }\n        throw new \\Exception('Should not happen');\n    }\n\n    /**\n     * @param array<int, array<int, int>> $trace\n     * @param T[] $old\n     * @param T[] $new\n     * @return DiffElem[]\n     */\n    private function extractDiff(array $trace, int $x, int $y, array $old, array $new): array {\n        $result = [];\n        for ($d = \\count($trace) - 1; $d >= 0; $d--) {\n            $v = $trace[$d];\n            $k = $x - $y;\n\n            if ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {\n                $prevK = $k + 1;\n            } else {\n                $prevK = $k - 1;\n            }\n\n            $prevX = $v[$prevK];\n            $prevY = $prevX - $prevK;\n\n            while ($x > $prevX && $y > $prevY) {\n                $result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]);\n                $x--;\n                $y--;\n            }\n\n            if ($d === 0) {\n                break;\n            }\n\n            while ($x > $prevX) {\n                $result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null);\n                $x--;\n            }\n\n            while ($y > $prevY) {\n                $result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]);\n                $y--;\n            }\n        }\n        return array_reverse($result);\n    }\n\n    /**\n     * Coalesce equal-length sequences of remove+add into a replace operation.\n     *\n     * @param DiffElem[] $diff\n     * @return DiffElem[]\n     */\n    private function coalesceReplacements(array $diff): array {\n        $newDiff = [];\n        $c = \\count($diff);\n        for ($i = 0; $i < $c; $i++) {\n            $diffType = $diff[$i]->type;\n            if ($diffType !== DiffElem::TYPE_REMOVE) {\n                $newDiff[] = $diff[$i];\n                continue;\n            }\n\n            $j = $i;\n            while ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) {\n                $j++;\n            }\n\n            $k = $j;\n            while ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) {\n                $k++;\n            }\n\n            if ($j - $i === $k - $j) {\n                $len = $j - $i;\n                for ($n = 0; $n < $len; $n++) {\n                    $newDiff[] = new DiffElem(\n                        DiffElem::TYPE_REPLACE, $diff[$i + $n]->old, $diff[$j + $n]->new\n                    );\n                }\n            } else {\n                for (; $i < $k; $i++) {\n                    $newDiff[] = $diff[$i];\n                }\n            }\n            $i = $k - 1;\n        }\n        return $newDiff;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal/PrintableNewAnonClassNode.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Internal;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\n\n/**\n * This node is used internally by the format-preserving pretty printer to print anonymous classes.\n *\n * The normal anonymous class structure violates assumptions about the order of token offsets.\n * Namely, the constructor arguments are part of the Expr\\New_ node and follow the class node, even\n * though they are actually interleaved with them. This special node type is used temporarily to\n * restore a sane token offset order.\n *\n * @internal\n */\nclass PrintableNewAnonClassNode extends Expr {\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n    /** @var int Modifiers */\n    public int $flags;\n    /** @var (Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder)[] Arguments */\n    public array $args;\n    /** @var null|Node\\Name Name of extended class */\n    public ?Node\\Name $extends;\n    /** @var Node\\Name[] Names of implemented interfaces */\n    public array $implements;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * @param Node\\AttributeGroup[] $attrGroups PHP attribute groups\n     * @param (Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder)[] $args Arguments\n     * @param Node\\Name|null $extends Name of extended class\n     * @param Node\\Name[] $implements Names of implemented interfaces\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Attributes\n     */\n    public function __construct(\n        array $attrGroups, int $flags, array $args, ?Node\\Name $extends, array $implements,\n        array $stmts, array $attributes\n    ) {\n        parent::__construct($attributes);\n        $this->attrGroups = $attrGroups;\n        $this->flags = $flags;\n        $this->args = $args;\n        $this->extends = $extends;\n        $this->implements = $implements;\n        $this->stmts = $stmts;\n    }\n\n    public static function fromNewNode(Expr\\New_ $newNode): self {\n        $class = $newNode->class;\n        assert($class instanceof Node\\Stmt\\Class_);\n        // We don't assert that $class->name is null here, to allow consumers to assign unique names\n        // to anonymous classes for their own purposes. We simplify ignore the name here.\n        return new self(\n            $class->attrGroups, $class->flags, $newNode->args, $class->extends, $class->implements,\n            $class->stmts, $newNode->getAttributes()\n        );\n    }\n\n    public function getType(): string {\n        return 'Expr_PrintableNewAnonClass';\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'args', 'extends', 'implements', 'stmts'];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal/TokenPolyfill.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Internal;\n\nif (\\PHP_VERSION_ID >= 80000) {\n    class TokenPolyfill extends \\PhpToken {\n    }\n    return;\n}\n\n/**\n * This is a polyfill for the PhpToken class introduced in PHP 8.0. We do not actually polyfill\n * PhpToken, because composer might end up picking a different polyfill implementation, which does\n * not meet our requirements.\n *\n * @internal\n */\nclass TokenPolyfill {\n    /** @var int The ID of the token. Either a T_* constant of a character code < 256. */\n    public int $id;\n    /** @var string The textual content of the token. */\n    public string $text;\n    /** @var int The 1-based starting line of the token (or -1 if unknown). */\n    public int $line;\n    /** @var int The 0-based starting position of the token (or -1 if unknown). */\n    public int $pos;\n\n    /** @var array<int, bool> Tokens ignored by the PHP parser. */\n    private const IGNORABLE_TOKENS = [\n        \\T_WHITESPACE => true,\n        \\T_COMMENT => true,\n        \\T_DOC_COMMENT => true,\n        \\T_OPEN_TAG => true,\n    ];\n\n    /** @var array<int, bool> Tokens that may be part of a T_NAME_* identifier. */\n    private static array $identifierTokens;\n\n    /**\n     * Create a Token with the given ID and text, as well optional line and position information.\n     */\n    final public function __construct(int $id, string $text, int $line = -1, int $pos = -1) {\n        $this->id = $id;\n        $this->text = $text;\n        $this->line = $line;\n        $this->pos = $pos;\n    }\n\n    /**\n     * Get the name of the token. For single-char tokens this will be the token character.\n     * Otherwise it will be a T_* style name, or null if the token ID is unknown.\n     */\n    public function getTokenName(): ?string {\n        if ($this->id < 256) {\n            return \\chr($this->id);\n        }\n\n        $name = token_name($this->id);\n        return $name === 'UNKNOWN' ? null : $name;\n    }\n\n    /**\n     * Check whether the token is of the given kind. The kind may be either an integer that matches\n     * the token ID, a string that matches the token text, or an array of integers/strings. In the\n     * latter case, the function returns true if any of the kinds in the array match.\n     *\n     * @param int|string|(int|string)[] $kind\n     */\n    public function is($kind): bool {\n        if (\\is_int($kind)) {\n            return $this->id === $kind;\n        }\n        if (\\is_string($kind)) {\n            return $this->text === $kind;\n        }\n        if (\\is_array($kind)) {\n            foreach ($kind as $entry) {\n                if (\\is_int($entry)) {\n                    if ($this->id === $entry) {\n                        return true;\n                    }\n                } elseif (\\is_string($entry)) {\n                    if ($this->text === $entry) {\n                        return true;\n                    }\n                } else {\n                    throw new \\TypeError(\n                        'Argument #1 ($kind) must only have elements of type string|int, ' .\n                        gettype($entry) . ' given');\n                }\n            }\n            return false;\n        }\n        throw new \\TypeError(\n            'Argument #1 ($kind) must be of type string|int|array, ' .gettype($kind) . ' given');\n    }\n\n    /**\n     * Check whether this token would be ignored by the PHP parser. Returns true for T_WHITESPACE,\n     * T_COMMENT, T_DOC_COMMENT and T_OPEN_TAG, and false for everything else.\n     */\n    public function isIgnorable(): bool {\n        return isset(self::IGNORABLE_TOKENS[$this->id]);\n    }\n\n    /**\n     * Return the textual content of the token.\n     */\n    public function __toString(): string {\n        return $this->text;\n    }\n\n    /**\n     * Tokenize the given source code and return an array of tokens.\n     *\n     * This performs certain canonicalizations to match the PHP 8.0 token format:\n     *  * Bad characters are represented using T_BAD_CHARACTER rather than omitted.\n     *  * T_COMMENT does not include trailing newlines, instead the newline is part of a following\n     *    T_WHITESPACE token.\n     *  * Namespaced names are represented using T_NAME_* tokens.\n     *\n     * @return static[]\n     */\n    public static function tokenize(string $code, int $flags = 0): array {\n        self::init();\n\n        $tokens = [];\n        $line = 1;\n        $pos = 0;\n        $origTokens = \\token_get_all($code, $flags);\n\n        $numTokens = \\count($origTokens);\n        for ($i = 0; $i < $numTokens; $i++) {\n            $token = $origTokens[$i];\n            if (\\is_string($token)) {\n                if (\\strlen($token) === 2) {\n                    // b\" and B\" are tokenized as single-char tokens, even though they aren't.\n                    $tokens[] = new static(\\ord('\"'), $token, $line, $pos);\n                    $pos += 2;\n                } else {\n                    $tokens[] = new static(\\ord($token), $token, $line, $pos);\n                    $pos++;\n                }\n            } else {\n                $id = $token[0];\n                $text = $token[1];\n\n                // Emulate PHP 8.0 comment format, which does not include trailing whitespace anymore.\n                if ($id === \\T_COMMENT && \\substr($text, 0, 2) !== '/*' &&\n                    \\preg_match('/(\\r\\n|\\n|\\r)$/D', $text, $matches)\n                ) {\n                    $trailingNewline = $matches[0];\n                    $text = \\substr($text, 0, -\\strlen($trailingNewline));\n                    $tokens[] = new static($id, $text, $line, $pos);\n                    $pos += \\strlen($text);\n\n                    if ($i + 1 < $numTokens && $origTokens[$i + 1][0] === \\T_WHITESPACE) {\n                        // Move trailing newline into following T_WHITESPACE token, if it already exists.\n                        $origTokens[$i + 1][1] = $trailingNewline . $origTokens[$i + 1][1];\n                        $origTokens[$i + 1][2]--;\n                    } else {\n                        // Otherwise, we need to create a new T_WHITESPACE token.\n                        $tokens[] = new static(\\T_WHITESPACE, $trailingNewline, $line, $pos);\n                        $line++;\n                        $pos += \\strlen($trailingNewline);\n                    }\n                    continue;\n                }\n\n                // Emulate PHP 8.0 T_NAME_* tokens, by combining sequences of T_NS_SEPARATOR and\n                // T_STRING into a single token.\n                if (($id === \\T_NS_SEPARATOR || isset(self::$identifierTokens[$id]))) {\n                    $newText = $text;\n                    $lastWasSeparator = $id === \\T_NS_SEPARATOR;\n                    for ($j = $i + 1; $j < $numTokens; $j++) {\n                        if ($lastWasSeparator) {\n                            if (!isset(self::$identifierTokens[$origTokens[$j][0]])) {\n                                break;\n                            }\n                            $lastWasSeparator = false;\n                        } else {\n                            if ($origTokens[$j][0] !== \\T_NS_SEPARATOR) {\n                                break;\n                            }\n                            $lastWasSeparator = true;\n                        }\n                        $newText .= $origTokens[$j][1];\n                    }\n                    if ($lastWasSeparator) {\n                        // Trailing separator is not part of the name.\n                        $j--;\n                        $newText = \\substr($newText, 0, -1);\n                    }\n                    if ($j > $i + 1) {\n                        if ($id === \\T_NS_SEPARATOR) {\n                            $id = \\T_NAME_FULLY_QUALIFIED;\n                        } elseif ($id === \\T_NAMESPACE) {\n                            $id = \\T_NAME_RELATIVE;\n                        } else {\n                            $id = \\T_NAME_QUALIFIED;\n                        }\n                        $tokens[] = new static($id, $newText, $line, $pos);\n                        $pos += \\strlen($newText);\n                        $i = $j - 1;\n                        continue;\n                    }\n                }\n\n                $tokens[] = new static($id, $text, $line, $pos);\n                $line += \\substr_count($text, \"\\n\");\n                $pos += \\strlen($text);\n            }\n        }\n        return $tokens;\n    }\n\n    /** Initialize private static state needed by tokenize(). */\n    private static function init(): void {\n        if (isset(self::$identifierTokens)) {\n            return;\n        }\n\n        // Based on semi_reserved production.\n        self::$identifierTokens = \\array_fill_keys([\n            \\T_STRING,\n            \\T_STATIC, \\T_ABSTRACT, \\T_FINAL, \\T_PRIVATE, \\T_PROTECTED, \\T_PUBLIC, \\T_READONLY,\n            \\T_INCLUDE, \\T_INCLUDE_ONCE, \\T_EVAL, \\T_REQUIRE, \\T_REQUIRE_ONCE, \\T_LOGICAL_OR, \\T_LOGICAL_XOR, \\T_LOGICAL_AND,\n            \\T_INSTANCEOF, \\T_NEW, \\T_CLONE, \\T_EXIT, \\T_IF, \\T_ELSEIF, \\T_ELSE, \\T_ENDIF, \\T_ECHO, \\T_DO, \\T_WHILE,\n            \\T_ENDWHILE, \\T_FOR, \\T_ENDFOR, \\T_FOREACH, \\T_ENDFOREACH, \\T_DECLARE, \\T_ENDDECLARE, \\T_AS, \\T_TRY, \\T_CATCH,\n            \\T_FINALLY, \\T_THROW, \\T_USE, \\T_INSTEADOF, \\T_GLOBAL, \\T_VAR, \\T_UNSET, \\T_ISSET, \\T_EMPTY, \\T_CONTINUE, \\T_GOTO,\n            \\T_FUNCTION, \\T_CONST, \\T_RETURN, \\T_PRINT, \\T_YIELD, \\T_LIST, \\T_SWITCH, \\T_ENDSWITCH, \\T_CASE, \\T_DEFAULT,\n            \\T_BREAK, \\T_ARRAY, \\T_CALLABLE, \\T_EXTENDS, \\T_IMPLEMENTS, \\T_NAMESPACE, \\T_TRAIT, \\T_INTERFACE, \\T_CLASS,\n            \\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,\n            \\T_MATCH,\n        ], true);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Internal/TokenStream.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Internal;\n\nuse PhpParser\\Token;\n\n/**\n * Provides operations on token streams, for use by pretty printer.\n *\n * @internal\n */\nclass TokenStream {\n    /** @var Token[] Tokens (in PhpToken::tokenize() format) */\n    private array $tokens;\n    /** @var int[] Map from position to indentation */\n    private array $indentMap;\n\n    /**\n     * Create token stream instance.\n     *\n     * @param Token[] $tokens Tokens in PhpToken::tokenize() format\n     */\n    public function __construct(array $tokens, int $tabWidth) {\n        $this->tokens = $tokens;\n        $this->indentMap = $this->calcIndentMap($tabWidth);\n    }\n\n    /**\n     * Whether the given position is immediately surrounded by parenthesis.\n     *\n     * @param int $startPos Start position\n     * @param int $endPos End position\n     */\n    public function haveParens(int $startPos, int $endPos): bool {\n        return $this->haveTokenImmediatelyBefore($startPos, '(')\n            && $this->haveTokenImmediatelyAfter($endPos, ')');\n    }\n\n    /**\n     * Whether the given position is immediately surrounded by braces.\n     *\n     * @param int $startPos Start position\n     * @param int $endPos End position\n     */\n    public function haveBraces(int $startPos, int $endPos): bool {\n        return ($this->haveTokenImmediatelyBefore($startPos, '{')\n                || $this->haveTokenImmediatelyBefore($startPos, T_CURLY_OPEN))\n            && $this->haveTokenImmediatelyAfter($endPos, '}');\n    }\n\n    /**\n     * Check whether the position is directly preceded by a certain token type.\n     *\n     * During this check whitespace and comments are skipped.\n     *\n     * @param int $pos Position before which the token should occur\n     * @param int|string $expectedTokenType Token to check for\n     *\n     * @return bool Whether the expected token was found\n     */\n    public function haveTokenImmediatelyBefore(int $pos, $expectedTokenType): bool {\n        $tokens = $this->tokens;\n        $pos--;\n        for (; $pos >= 0; $pos--) {\n            $token = $tokens[$pos];\n            if ($token->is($expectedTokenType)) {\n                return true;\n            }\n            if (!$token->isIgnorable()) {\n                break;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Check whether the position is directly followed by a certain token type.\n     *\n     * During this check whitespace and comments are skipped.\n     *\n     * @param int $pos Position after which the token should occur\n     * @param int|string $expectedTokenType Token to check for\n     *\n     * @return bool Whether the expected token was found\n     */\n    public function haveTokenImmediatelyAfter(int $pos, $expectedTokenType): bool {\n        $tokens = $this->tokens;\n        $pos++;\n        for ($c = \\count($tokens); $pos < $c; $pos++) {\n            $token = $tokens[$pos];\n            if ($token->is($expectedTokenType)) {\n                return true;\n            }\n            if (!$token->isIgnorable()) {\n                break;\n            }\n        }\n        return false;\n    }\n\n    /** @param int|string|(int|string)[] $skipTokenType */\n    public function skipLeft(int $pos, $skipTokenType): int {\n        $tokens = $this->tokens;\n\n        $pos = $this->skipLeftWhitespace($pos);\n        if ($skipTokenType === \\T_WHITESPACE) {\n            return $pos;\n        }\n\n        if (!$tokens[$pos]->is($skipTokenType)) {\n            // Shouldn't happen. The skip token MUST be there\n            throw new \\Exception('Encountered unexpected token');\n        }\n        $pos--;\n\n        return $this->skipLeftWhitespace($pos);\n    }\n\n    /** @param int|string|(int|string)[] $skipTokenType */\n    public function skipRight(int $pos, $skipTokenType): int {\n        $tokens = $this->tokens;\n\n        $pos = $this->skipRightWhitespace($pos);\n        if ($skipTokenType === \\T_WHITESPACE) {\n            return $pos;\n        }\n\n        if (!$tokens[$pos]->is($skipTokenType)) {\n            // Shouldn't happen. The skip token MUST be there\n            throw new \\Exception('Encountered unexpected token');\n        }\n        $pos++;\n\n        return $this->skipRightWhitespace($pos);\n    }\n\n    /**\n     * Return first non-whitespace token position smaller or equal to passed position.\n     *\n     * @param int $pos Token position\n     * @return int Non-whitespace token position\n     */\n    public function skipLeftWhitespace(int $pos): int {\n        $tokens = $this->tokens;\n        for (; $pos >= 0; $pos--) {\n            if (!$tokens[$pos]->isIgnorable()) {\n                break;\n            }\n        }\n        return $pos;\n    }\n\n    /**\n     * Return first non-whitespace position greater or equal to passed position.\n     *\n     * @param int $pos Token position\n     * @return int Non-whitespace token position\n     */\n    public function skipRightWhitespace(int $pos): int {\n        $tokens = $this->tokens;\n        for ($count = \\count($tokens); $pos < $count; $pos++) {\n            if (!$tokens[$pos]->isIgnorable()) {\n                break;\n            }\n        }\n        return $pos;\n    }\n\n    /** @param int|string|(int|string)[] $findTokenType */\n    public function findRight(int $pos, $findTokenType): int {\n        $tokens = $this->tokens;\n        for ($count = \\count($tokens); $pos < $count; $pos++) {\n            if ($tokens[$pos]->is($findTokenType)) {\n                return $pos;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * Whether the given position range contains a certain token type.\n     *\n     * @param int $startPos Starting position (inclusive)\n     * @param int $endPos Ending position (exclusive)\n     * @param int|string $tokenType Token type to look for\n     * @return bool Whether the token occurs in the given range\n     */\n    public function haveTokenInRange(int $startPos, int $endPos, $tokenType): bool {\n        $tokens = $this->tokens;\n        for ($pos = $startPos; $pos < $endPos; $pos++) {\n            if ($tokens[$pos]->is($tokenType)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public function haveTagInRange(int $startPos, int $endPos): bool {\n        return $this->haveTokenInRange($startPos, $endPos, \\T_OPEN_TAG)\n            || $this->haveTokenInRange($startPos, $endPos, \\T_CLOSE_TAG);\n    }\n\n    /**\n     * Get indentation before token position.\n     *\n     * @param int $pos Token position\n     *\n     * @return int Indentation depth (in spaces)\n     */\n    public function getIndentationBefore(int $pos): int {\n        return $this->indentMap[$pos];\n    }\n\n    /**\n     * Get the code corresponding to a token offset range, optionally adjusted for indentation.\n     *\n     * @param int $from Token start position (inclusive)\n     * @param int $to Token end position (exclusive)\n     * @param int $indent By how much the code should be indented (can be negative as well)\n     *\n     * @return string Code corresponding to token range, adjusted for indentation\n     */\n    public function getTokenCode(int $from, int $to, int $indent): string {\n        $tokens = $this->tokens;\n        $result = '';\n        for ($pos = $from; $pos < $to; $pos++) {\n            $token = $tokens[$pos];\n            $id = $token->id;\n            $text = $token->text;\n            if ($id === \\T_CONSTANT_ENCAPSED_STRING || $id === \\T_ENCAPSED_AND_WHITESPACE) {\n                $result .= $text;\n            } else {\n                // TODO Handle non-space indentation\n                if ($indent < 0) {\n                    $result .= str_replace(\"\\n\" . str_repeat(\" \", -$indent), \"\\n\", $text);\n                } elseif ($indent > 0) {\n                    $result .= str_replace(\"\\n\", \"\\n\" . str_repeat(\" \", $indent), $text);\n                } else {\n                    $result .= $text;\n                }\n            }\n        }\n        return $result;\n    }\n\n    /**\n     * Precalculate the indentation at every token position.\n     *\n     * @return int[] Token position to indentation map\n     */\n    private function calcIndentMap(int $tabWidth): array {\n        $indentMap = [];\n        $indent = 0;\n        foreach ($this->tokens as $i => $token) {\n            $indentMap[] = $indent;\n\n            if ($token->id === \\T_WHITESPACE) {\n                $content = $token->text;\n                $newlinePos = \\strrpos($content, \"\\n\");\n                if (false !== $newlinePos) {\n                    $indent = $this->getIndent(\\substr($content, $newlinePos + 1), $tabWidth);\n                } elseif ($i === 1 && $this->tokens[0]->id === \\T_OPEN_TAG &&\n                          $this->tokens[0]->text[\\strlen($this->tokens[0]->text) - 1] === \"\\n\") {\n                    // Special case: Newline at the end of opening tag followed by whitespace.\n                    $indent = $this->getIndent($content, $tabWidth);\n                }\n            }\n        }\n\n        // Add a sentinel for one past end of the file\n        $indentMap[] = $indent;\n\n        return $indentMap;\n    }\n\n    private function getIndent(string $ws, int $tabWidth): int {\n        $spaces = \\substr_count($ws, \" \");\n        $tabs = \\substr_count($ws, \"\\t\");\n        assert(\\strlen($ws) === $spaces + $tabs);\n        return $spaces + $tabs * $tabWidth;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/JsonDecoder.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nclass JsonDecoder {\n    /** @var \\ReflectionClass<Node>[] Node type to reflection class map */\n    private array $reflectionClassCache;\n\n    /** @return mixed */\n    public function decode(string $json) {\n        $value = json_decode($json, true);\n        if (json_last_error()) {\n            throw new \\RuntimeException('JSON decoding error: ' . json_last_error_msg());\n        }\n\n        return $this->decodeRecursive($value);\n    }\n\n    /**\n     * @param mixed $value\n     * @return mixed\n     */\n    private function decodeRecursive($value) {\n        if (\\is_array($value)) {\n            if (isset($value['nodeType'])) {\n                if ($value['nodeType'] === 'Comment' || $value['nodeType'] === 'Comment_Doc') {\n                    return $this->decodeComment($value);\n                }\n                return $this->decodeNode($value);\n            }\n            return $this->decodeArray($value);\n        }\n        return $value;\n    }\n\n    private function decodeArray(array $array): array {\n        $decodedArray = [];\n        foreach ($array as $key => $value) {\n            $decodedArray[$key] = $this->decodeRecursive($value);\n        }\n        return $decodedArray;\n    }\n\n    private function decodeNode(array $value): Node {\n        $nodeType = $value['nodeType'];\n        if (!\\is_string($nodeType)) {\n            throw new \\RuntimeException('Node type must be a string');\n        }\n\n        $reflectionClass = $this->reflectionClassFromNodeType($nodeType);\n        $node = $reflectionClass->newInstanceWithoutConstructor();\n\n        if (isset($value['attributes'])) {\n            if (!\\is_array($value['attributes'])) {\n                throw new \\RuntimeException('Attributes must be an array');\n            }\n\n            $node->setAttributes($this->decodeArray($value['attributes']));\n        }\n\n        foreach ($value as $name => $subNode) {\n            if ($name === 'nodeType' || $name === 'attributes') {\n                continue;\n            }\n\n            $node->$name = $this->decodeRecursive($subNode);\n        }\n\n        return $node;\n    }\n\n    private function decodeComment(array $value): Comment {\n        $className = $value['nodeType'] === 'Comment' ? Comment::class : Comment\\Doc::class;\n        if (!isset($value['text'])) {\n            throw new \\RuntimeException('Comment must have text');\n        }\n\n        return new $className(\n            $value['text'],\n            $value['line'] ?? -1, $value['filePos'] ?? -1, $value['tokenPos'] ?? -1,\n            $value['endLine'] ?? -1, $value['endFilePos'] ?? -1, $value['endTokenPos'] ?? -1\n        );\n    }\n\n    /** @return \\ReflectionClass<Node> */\n    private function reflectionClassFromNodeType(string $nodeType): \\ReflectionClass {\n        if (!isset($this->reflectionClassCache[$nodeType])) {\n            $className = $this->classNameFromNodeType($nodeType);\n            $this->reflectionClassCache[$nodeType] = new \\ReflectionClass($className);\n        }\n        return $this->reflectionClassCache[$nodeType];\n    }\n\n    /** @return class-string<Node> */\n    private function classNameFromNodeType(string $nodeType): string {\n        $className = 'PhpParser\\\\Node\\\\' . strtr($nodeType, '_', '\\\\');\n        if (class_exists($className)) {\n            return $className;\n        }\n\n        $className .= '_';\n        if (class_exists($className)) {\n            return $className;\n        }\n\n        throw new \\RuntimeException(\"Unknown node type \\\"$nodeType\\\"\");\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/Emulative.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer;\n\nuse PhpParser\\Error;\nuse PhpParser\\ErrorHandler;\nuse PhpParser\\Lexer;\nuse PhpParser\\Lexer\\TokenEmulator\\AsymmetricVisibilityTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\AttributeEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\EnumTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\ExplicitOctalEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\FnTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\MatchTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\NullsafeTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\PipeOperatorEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\PropertyTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\ReadonlyFunctionTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\ReadonlyTokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\ReverseEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\TokenEmulator;\nuse PhpParser\\Lexer\\TokenEmulator\\VoidCastEmulator;\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nclass Emulative extends Lexer {\n    /** @var array{int, string, string}[] Patches used to reverse changes introduced in the code */\n    private array $patches = [];\n\n    /** @var list<TokenEmulator> */\n    private array $emulators = [];\n\n    private PhpVersion $targetPhpVersion;\n\n    private PhpVersion $hostPhpVersion;\n\n    /**\n     * @param PhpVersion|null $phpVersion PHP version to emulate. Defaults to newest supported.\n     */\n    public function __construct(?PhpVersion $phpVersion = null) {\n        $this->targetPhpVersion = $phpVersion ?? PhpVersion::getNewestSupported();\n        $this->hostPhpVersion = PhpVersion::getHostVersion();\n\n        $emulators = [\n            new FnTokenEmulator(),\n            new MatchTokenEmulator(),\n            new NullsafeTokenEmulator(),\n            new AttributeEmulator(),\n            new EnumTokenEmulator(),\n            new ReadonlyTokenEmulator(),\n            new ExplicitOctalEmulator(),\n            new ReadonlyFunctionTokenEmulator(),\n            new PropertyTokenEmulator(),\n            new AsymmetricVisibilityTokenEmulator(),\n            new PipeOperatorEmulator(),\n            new VoidCastEmulator(),\n        ];\n\n        // Collect emulators that are relevant for the PHP version we're running\n        // and the PHP version we're targeting for emulation.\n        foreach ($emulators as $emulator) {\n            $emulatorPhpVersion = $emulator->getPhpVersion();\n            if ($this->isForwardEmulationNeeded($emulatorPhpVersion)) {\n                $this->emulators[] = $emulator;\n            } elseif ($this->isReverseEmulationNeeded($emulatorPhpVersion)) {\n                $this->emulators[] = new ReverseEmulator($emulator);\n            }\n        }\n    }\n\n    public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array {\n        $emulators = array_filter($this->emulators, function ($emulator) use ($code) {\n            return $emulator->isEmulationNeeded($code);\n        });\n\n        if (empty($emulators)) {\n            // Nothing to emulate, yay\n            return parent::tokenize($code, $errorHandler);\n        }\n\n        if ($errorHandler === null) {\n            $errorHandler = new ErrorHandler\\Throwing();\n        }\n\n        $this->patches = [];\n        foreach ($emulators as $emulator) {\n            $code = $emulator->preprocessCode($code, $this->patches);\n        }\n\n        $collector = new ErrorHandler\\Collecting();\n        $tokens = parent::tokenize($code, $collector);\n        $this->sortPatches();\n        $tokens = $this->fixupTokens($tokens);\n\n        $errors = $collector->getErrors();\n        if (!empty($errors)) {\n            $this->fixupErrors($errors);\n            foreach ($errors as $error) {\n                $errorHandler->handleError($error);\n            }\n        }\n\n        foreach ($emulators as $emulator) {\n            $tokens = $emulator->emulate($code, $tokens);\n        }\n\n        return $tokens;\n    }\n\n    private function isForwardEmulationNeeded(PhpVersion $emulatorPhpVersion): bool {\n        return $this->hostPhpVersion->older($emulatorPhpVersion)\n            && $this->targetPhpVersion->newerOrEqual($emulatorPhpVersion);\n    }\n\n    private function isReverseEmulationNeeded(PhpVersion $emulatorPhpVersion): bool {\n        return $this->hostPhpVersion->newerOrEqual($emulatorPhpVersion)\n            && $this->targetPhpVersion->older($emulatorPhpVersion);\n    }\n\n    private function sortPatches(): void {\n        // Patches may be contributed by different emulators.\n        // Make sure they are sorted by increasing patch position.\n        usort($this->patches, function ($p1, $p2) {\n            return $p1[0] <=> $p2[0];\n        });\n    }\n\n    /**\n     * @param list<Token> $tokens\n     * @return list<Token>\n     */\n    private function fixupTokens(array $tokens): array {\n        if (\\count($this->patches) === 0) {\n            return $tokens;\n        }\n\n        // Load first patch\n        $patchIdx = 0;\n        list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx];\n\n        // We use a manual loop over the tokens, because we modify the array on the fly\n        $posDelta = 0;\n        $lineDelta = 0;\n        for ($i = 0, $c = \\count($tokens); $i < $c; $i++) {\n            $token = $tokens[$i];\n            $pos = $token->pos;\n            $token->pos += $posDelta;\n            $token->line += $lineDelta;\n            $localPosDelta = 0;\n            $len = \\strlen($token->text);\n            while ($patchPos >= $pos && $patchPos < $pos + $len) {\n                $patchTextLen = \\strlen($patchText);\n                if ($patchType === 'remove') {\n                    if ($patchPos === $pos && $patchTextLen === $len) {\n                        // Remove token entirely\n                        array_splice($tokens, $i, 1, []);\n                        $i--;\n                        $c--;\n                    } else {\n                        // Remove from token string\n                        $token->text = substr_replace(\n                            $token->text, '', $patchPos - $pos + $localPosDelta, $patchTextLen\n                        );\n                        $localPosDelta -= $patchTextLen;\n                    }\n                    $lineDelta -= \\substr_count($patchText, \"\\n\");\n                } elseif ($patchType === 'add') {\n                    // Insert into the token string\n                    $token->text = substr_replace(\n                        $token->text, $patchText, $patchPos - $pos + $localPosDelta, 0\n                    );\n                    $localPosDelta += $patchTextLen;\n                    $lineDelta += \\substr_count($patchText, \"\\n\");\n                } elseif ($patchType === 'replace') {\n                    // Replace inside the token string\n                    $token->text = substr_replace(\n                        $token->text, $patchText, $patchPos - $pos + $localPosDelta, $patchTextLen\n                    );\n                } else {\n                    assert(false);\n                }\n\n                // Fetch the next patch\n                $patchIdx++;\n                if ($patchIdx >= \\count($this->patches)) {\n                    // No more patches. However, we still need to adjust position.\n                    $patchPos = \\PHP_INT_MAX;\n                    break;\n                }\n\n                list($patchPos, $patchType, $patchText) = $this->patches[$patchIdx];\n            }\n\n            $posDelta += $localPosDelta;\n        }\n        return $tokens;\n    }\n\n    /**\n     * Fixup line and position information in errors.\n     *\n     * @param Error[] $errors\n     */\n    private function fixupErrors(array $errors): void {\n        foreach ($errors as $error) {\n            $attrs = $error->getAttributes();\n\n            $posDelta = 0;\n            $lineDelta = 0;\n            foreach ($this->patches as $patch) {\n                list($patchPos, $patchType, $patchText) = $patch;\n                if ($patchPos >= $attrs['startFilePos']) {\n                    // No longer relevant\n                    break;\n                }\n\n                if ($patchType === 'add') {\n                    $posDelta += strlen($patchText);\n                    $lineDelta += substr_count($patchText, \"\\n\");\n                } elseif ($patchType === 'remove') {\n                    $posDelta -= strlen($patchText);\n                    $lineDelta -= substr_count($patchText, \"\\n\");\n                }\n            }\n\n            $attrs['startFilePos'] += $posDelta;\n            $attrs['endFilePos'] += $posDelta;\n            $attrs['startLine'] += $lineDelta;\n            $attrs['endLine'] += $lineDelta;\n            $error->setAttributes($attrs);\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AsymmetricVisibilityTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nfinal class AsymmetricVisibilityTokenEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 4);\n    }\n    public function isEmulationNeeded(string $code): bool {\n        $code = strtolower($code);\n        return strpos($code, 'public(set)') !== false ||\n            strpos($code, 'protected(set)') !== false ||\n            strpos($code, 'private(set)') !== false;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        $map = [\n            \\T_PUBLIC => \\T_PUBLIC_SET,\n            \\T_PROTECTED => \\T_PROTECTED_SET,\n            \\T_PRIVATE => \\T_PRIVATE_SET,\n        ];\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if (isset($map[$token->id]) && $i + 3 < $c && $tokens[$i + 1]->text === '(' &&\n                $tokens[$i + 2]->id === \\T_STRING && \\strtolower($tokens[$i + 2]->text) === 'set' &&\n                $tokens[$i + 3]->text === ')' &&\n                $this->isKeywordContext($tokens, $i)\n            ) {\n                array_splice($tokens, $i, 4, [\n                    new Token(\n                        $map[$token->id], $token->text . '(' . $tokens[$i + 2]->text . ')',\n                        $token->line, $token->pos),\n                ]);\n                $c -= 3;\n            }\n        }\n\n        return $tokens;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        $reverseMap = [\n            \\T_PUBLIC_SET => \\T_PUBLIC,\n            \\T_PROTECTED_SET => \\T_PROTECTED,\n            \\T_PRIVATE_SET => \\T_PRIVATE,\n        ];\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if (isset($reverseMap[$token->id]) &&\n                \\preg_match('/(public|protected|private)\\((set)\\)/i', $token->text, $matches)\n            ) {\n                [, $modifier, $set] = $matches;\n                $modifierLen = \\strlen($modifier);\n                array_splice($tokens, $i, 1, [\n                    new Token($reverseMap[$token->id], $modifier, $token->line, $token->pos),\n                    new Token(\\ord('('), '(', $token->line, $token->pos + $modifierLen),\n                    new Token(\\T_STRING, $set, $token->line, $token->pos + $modifierLen + 1),\n                    new Token(\\ord(')'), ')', $token->line, $token->pos + $modifierLen + 4),\n                ]);\n                $i += 3;\n                $c += 3;\n            }\n        }\n\n        return $tokens;\n    }\n\n    /** @param Token[] $tokens */\n    protected function isKeywordContext(array $tokens, int $pos): bool {\n        $prevToken = $this->getPreviousNonSpaceToken($tokens, $pos);\n        if ($prevToken === null) {\n            return false;\n        }\n        return $prevToken->id !== \\T_OBJECT_OPERATOR\n            && $prevToken->id !== \\T_NULLSAFE_OBJECT_OPERATOR;\n    }\n\n    /** @param Token[] $tokens */\n    private function getPreviousNonSpaceToken(array $tokens, int $start): ?Token {\n        for ($i = $start - 1; $i >= 0; --$i) {\n            if ($tokens[$i]->id === T_WHITESPACE) {\n                continue;\n            }\n\n            return $tokens[$i];\n        }\n\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/AttributeEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nfinal class AttributeEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 0);\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return strpos($code, '#[') !== false;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        // We need to manually iterate and manage a count because we'll change\n        // the tokens array on the way.\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->text === '#' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '[') {\n                array_splice($tokens, $i, 2, [\n                    new Token(\\T_ATTRIBUTE, '#[', $token->line, $token->pos),\n                ]);\n                $c--;\n                continue;\n            }\n        }\n\n        return $tokens;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        // TODO\n        return $tokens;\n    }\n\n    public function preprocessCode(string $code, array &$patches): string {\n        $pos = 0;\n        while (false !== $pos = strpos($code, '#[', $pos)) {\n            // Replace #[ with %[\n            $code[$pos] = '%';\n            $patches[] = [$pos, 'replace', '#'];\n            $pos += 2;\n        }\n        return $code;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/EnumTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\nfinal class EnumTokenEmulator extends KeywordEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 1);\n    }\n\n    public function getKeywordString(): string {\n        return 'enum';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_ENUM;\n    }\n\n    protected function isKeywordContext(array $tokens, int $pos): bool {\n        return parent::isKeywordContext($tokens, $pos)\n            && isset($tokens[$pos + 2])\n            && $tokens[$pos + 1]->id === \\T_WHITESPACE\n            && $tokens[$pos + 2]->id === \\T_STRING;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ExplicitOctalEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nclass ExplicitOctalEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 1);\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return strpos($code, '0o') !== false || strpos($code, '0O') !== false;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->id == \\T_LNUMBER && $token->text === '0' &&\n                isset($tokens[$i + 1]) && $tokens[$i + 1]->id == \\T_STRING &&\n                preg_match('/[oO][0-7]+(?:_[0-7]+)*/', $tokens[$i + 1]->text)\n            ) {\n                $tokenKind = $this->resolveIntegerOrFloatToken($tokens[$i + 1]->text);\n                array_splice($tokens, $i, 2, [\n                    new Token($tokenKind, '0' . $tokens[$i + 1]->text, $token->line, $token->pos),\n                ]);\n                $c--;\n            }\n        }\n        return $tokens;\n    }\n\n    private function resolveIntegerOrFloatToken(string $str): int {\n        $str = substr($str, 1);\n        $str = str_replace('_', '', $str);\n        $num = octdec($str);\n        return is_float($num) ? \\T_DNUMBER : \\T_LNUMBER;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        // Explicit octals were not legal code previously, don't bother.\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/FnTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\n// Retained for reverse emulation support only.\nfinal class FnTokenEmulator extends KeywordEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromString('7.4');\n    }\n\n    public function getKeywordString(): string {\n        return 'fn';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_FN;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/KeywordEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\Token;\n\nabstract class KeywordEmulator extends TokenEmulator {\n    abstract public function getKeywordString(): string;\n    abstract public function getKeywordToken(): int;\n\n    public function isEmulationNeeded(string $code): bool {\n        return strpos(strtolower($code), $this->getKeywordString()) !== false;\n    }\n\n    /** @param Token[] $tokens */\n    protected function isKeywordContext(array $tokens, int $pos): bool {\n        $prevToken = $this->getPreviousNonIgnorableToken($tokens, $pos);\n        if ($prevToken === null) {\n            return false;\n        }\n        return $prevToken->id !== \\T_OBJECT_OPERATOR\n            && $prevToken->id !== \\T_NULLSAFE_OBJECT_OPERATOR;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        $keywordString = $this->getKeywordString();\n        foreach ($tokens as $i => $token) {\n            if ($token->id === T_STRING && strtolower($token->text) === $keywordString\n                    && $this->isKeywordContext($tokens, $i)) {\n                $token->id = $this->getKeywordToken();\n            }\n        }\n\n        return $tokens;\n    }\n\n    /** @param Token[] $tokens */\n    private function getPreviousNonIgnorableToken(array $tokens, int $start): ?Token {\n        for ($i = $start - 1; $i >= 0; --$i) {\n            $token = $tokens[$i];\n            if ($token->id === T_WHITESPACE || $token->id == T_COMMENT || $token->id === T_DOC_COMMENT) {\n                continue;\n            }\n\n            return $token;\n        }\n\n        return null;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        $keywordToken = $this->getKeywordToken();\n        foreach ($tokens as $token) {\n            if ($token->id === $keywordToken) {\n                $token->id = \\T_STRING;\n            }\n        }\n\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/MatchTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\nfinal class MatchTokenEmulator extends KeywordEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 0);\n    }\n\n    public function getKeywordString(): string {\n        return 'match';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_MATCH;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/NullsafeTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nfinal class NullsafeTokenEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 0);\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return strpos($code, '?->') !== false;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        // We need to manually iterate and manage a count because we'll change\n        // the tokens array on the way\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->text === '?' && isset($tokens[$i + 1]) && $tokens[$i + 1]->id === \\T_OBJECT_OPERATOR) {\n                array_splice($tokens, $i, 2, [\n                    new Token(\\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos),\n                ]);\n                $c--;\n                continue;\n            }\n\n            // Handle ?-> inside encapsed string.\n            if ($token->id === \\T_ENCAPSED_AND_WHITESPACE && isset($tokens[$i - 1])\n                && $tokens[$i - 1]->id === \\T_VARIABLE\n                && preg_match('/^\\?->([a-zA-Z_\\x80-\\xff][a-zA-Z0-9_\\x80-\\xff]*)/', $token->text, $matches)\n            ) {\n                $replacement = [\n                    new Token(\\T_NULLSAFE_OBJECT_OPERATOR, '?->', $token->line, $token->pos),\n                    new Token(\\T_STRING, $matches[1], $token->line, $token->pos + 3),\n                ];\n                $matchLen = \\strlen($matches[0]);\n                if ($matchLen !== \\strlen($token->text)) {\n                    $replacement[] = new Token(\n                        \\T_ENCAPSED_AND_WHITESPACE,\n                        \\substr($token->text, $matchLen),\n                        $token->line, $token->pos + $matchLen\n                    );\n                }\n                array_splice($tokens, $i, 1, $replacement);\n                $c += \\count($replacement) - 1;\n                continue;\n            }\n        }\n\n        return $tokens;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        // ?-> was not valid code previously, don't bother.\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/PipeOperatorEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\Lexer\\TokenEmulator\\TokenEmulator;\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nclass PipeOperatorEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 5);\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return \\strpos($code, '|>') !== false;\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->text === '|' && isset($tokens[$i + 1]) && $tokens[$i + 1]->text === '>') {\n                array_splice($tokens, $i, 2, [\n                    new Token(\\T_PIPE, '|>', $token->line, $token->pos),\n                ]);\n                $c--;\n            }\n        }\n        return $tokens;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->id === \\T_PIPE) {\n                array_splice($tokens, $i, 1, [\n                    new Token(\\ord('|'), '|', $token->line, $token->pos),\n                    new Token(\\ord('>'), '>', $token->line, $token->pos + 1),\n                ]);\n                $i++;\n                $c++;\n            }\n        }\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/PropertyTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\nfinal class PropertyTokenEmulator extends KeywordEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 4);\n    }\n\n    public function getKeywordString(): string {\n        return '__property__';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_PROPERTY_C;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyFunctionTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\n/*\n * In PHP 8.1, \"readonly(\" was special cased in the lexer in order to support functions with\n * name readonly. In PHP 8.2, this may conflict with readonly properties having a DNF type. For\n * this reason, PHP 8.2 instead treats this as T_READONLY and then handles it specially in the\n * parser. This emulator only exists to handle this special case, which is skipped by the\n * PHP 8.1 ReadonlyTokenEmulator.\n */\nclass ReadonlyFunctionTokenEmulator extends KeywordEmulator {\n    public function getKeywordString(): string {\n        return 'readonly';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_READONLY;\n    }\n\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 2);\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        // Don't bother\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReadonlyTokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\nfinal class ReadonlyTokenEmulator extends KeywordEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 1);\n    }\n\n    public function getKeywordString(): string {\n        return 'readonly';\n    }\n\n    public function getKeywordToken(): int {\n        return \\T_READONLY;\n    }\n\n    protected function isKeywordContext(array $tokens, int $pos): bool {\n        if (!parent::isKeywordContext($tokens, $pos)) {\n            return false;\n        }\n        // Support \"function readonly(\"\n        return !(isset($tokens[$pos + 1]) &&\n                 ($tokens[$pos + 1]->text === '(' ||\n                  ($tokens[$pos + 1]->id === \\T_WHITESPACE &&\n                   isset($tokens[$pos + 2]) &&\n                   $tokens[$pos + 2]->text === '(')));\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/ReverseEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\n\n/**\n * Reverses emulation direction of the inner emulator.\n */\nfinal class ReverseEmulator extends TokenEmulator {\n    /** @var TokenEmulator Inner emulator */\n    private TokenEmulator $emulator;\n\n    public function __construct(TokenEmulator $emulator) {\n        $this->emulator = $emulator;\n    }\n\n    public function getPhpVersion(): PhpVersion {\n        return $this->emulator->getPhpVersion();\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return $this->emulator->isEmulationNeeded($code);\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        return $this->emulator->reverseEmulate($code, $tokens);\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        return $this->emulator->emulate($code, $tokens);\n    }\n\n    public function preprocessCode(string $code, array &$patches): string {\n        return $code;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/TokenEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\n/** @internal */\nabstract class TokenEmulator {\n    abstract public function getPhpVersion(): PhpVersion;\n\n    abstract public function isEmulationNeeded(string $code): bool;\n\n    /**\n     * @param Token[] $tokens Original tokens\n     * @return Token[] Modified Tokens\n     */\n    abstract public function emulate(string $code, array $tokens): array;\n\n    /**\n     * @param Token[] $tokens Original tokens\n     * @return Token[] Modified Tokens\n     */\n    abstract public function reverseEmulate(string $code, array $tokens): array;\n\n    /** @param array{int, string, string}[] $patches */\n    public function preprocessCode(string $code, array &$patches): string {\n        return $code;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer/TokenEmulator/VoidCastEmulator.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Lexer\\TokenEmulator;\n\nuse PhpParser\\PhpVersion;\nuse PhpParser\\Token;\n\nclass VoidCastEmulator extends TokenEmulator {\n    public function getPhpVersion(): PhpVersion {\n        return PhpVersion::fromComponents(8, 5);\n    }\n\n    public function isEmulationNeeded(string $code): bool {\n        return (bool)\\preg_match('/\\([ \\t]*void[ \\t]*\\)/i', $code);\n    }\n\n    public function emulate(string $code, array $tokens): array {\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->text !== '(') {\n                continue;\n            }\n\n            $numTokens = 1;\n            $text = '(';\n            $j = $i + 1;\n            if ($j < $c && $tokens[$j]->id === \\T_WHITESPACE && preg_match('/\\A[ \\t]+\\z/', $tokens[$j]->text)) {\n                $text .= $tokens[$j]->text;\n                $numTokens++;\n                $j++;\n            }\n\n            if ($j >= $c || $tokens[$j]->id !== \\T_STRING || \\strtolower($tokens[$j]->text) !== 'void') {\n                continue;\n            }\n\n            $text .= $tokens[$j]->text;\n            $numTokens++;\n            $k = $j + 1;\n            if ($k < $c && $tokens[$k]->id === \\T_WHITESPACE && preg_match('/\\A[ \\t]+\\z/', $tokens[$k]->text)) {\n                $text .= $tokens[$k]->text;\n                $numTokens++;\n                $k++;\n            }\n\n            if ($k >= $c || $tokens[$k]->text !== ')') {\n                continue;\n            }\n\n            $text .= ')';\n            $numTokens++;\n            array_splice($tokens, $i, $numTokens, [\n                new Token(\\T_VOID_CAST, $text, $token->line, $token->pos),\n            ]);\n            $c -= $numTokens - 1;\n        }\n        return $tokens;\n    }\n\n    public function reverseEmulate(string $code, array $tokens): array {\n        for ($i = 0, $c = count($tokens); $i < $c; ++$i) {\n            $token = $tokens[$i];\n            if ($token->id !== \\T_VOID_CAST) {\n                continue;\n            }\n\n            if (!preg_match('/^\\(([ \\t]*)(void)([ \\t]*)\\)$/i', $token->text, $match)) {\n                throw new \\LogicException('Unexpected T_VOID_CAST contents');\n            }\n\n            $newTokens = [];\n            $pos = $token->pos;\n\n            $newTokens[] = new Token(\\ord('('), '(', $token->line, $pos);\n            $pos++;\n\n            if ($match[1] !== '') {\n                $newTokens[] = new Token(\\T_WHITESPACE, $match[1], $token->line, $pos);\n                $pos += \\strlen($match[1]);\n            }\n\n            $newTokens[] = new Token(\\T_STRING, $match[2], $token->line, $pos);\n            $pos += \\strlen($match[2]);\n\n            if ($match[3] !== '') {\n                $newTokens[] = new Token(\\T_WHITESPACE, $match[3], $token->line, $pos);\n                $pos += \\strlen($match[3]);\n            }\n\n            $newTokens[] = new Token(\\ord(')'), ')', $token->line, $pos);\n\n            array_splice($tokens, $i, 1, $newTokens);\n            $i += \\count($newTokens) - 1;\n            $c += \\count($newTokens) - 1;\n        }\n        return $tokens;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Lexer.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nrequire __DIR__ . '/compatibility_tokens.php';\n\nclass Lexer {\n    /**\n     * Tokenize the provided source code.\n     *\n     * The token array is in the same format as provided by the PhpToken::tokenize() method in\n     * PHP 8.0. The tokens are instances of PhpParser\\Token, to abstract over a polyfill\n     * implementation in earlier PHP version.\n     *\n     * The token array is terminated by a sentinel token with token ID 0.\n     * The token array does not discard any tokens (i.e. whitespace and comments are included).\n     * The token position attributes are against this token array.\n     *\n     * @param string $code The source code to tokenize.\n     * @param ErrorHandler|null $errorHandler Error handler to use for lexing errors. Defaults to\n     *                                        ErrorHandler\\Throwing.\n     * @return Token[] Tokens\n     */\n    public function tokenize(string $code, ?ErrorHandler $errorHandler = null): array {\n        if (null === $errorHandler) {\n            $errorHandler = new ErrorHandler\\Throwing();\n        }\n\n        $scream = ini_set('xdebug.scream', '0');\n\n        $tokens = @Token::tokenize($code);\n        $this->postprocessTokens($tokens, $errorHandler);\n\n        if (false !== $scream) {\n            ini_set('xdebug.scream', $scream);\n        }\n\n        return $tokens;\n    }\n\n    private function handleInvalidCharacter(Token $token, ErrorHandler $errorHandler): void {\n        $chr = $token->text;\n        if ($chr === \"\\0\") {\n            // PHP cuts error message after null byte, so need special case\n            $errorMsg = 'Unexpected null byte';\n        } else {\n            $errorMsg = sprintf(\n                'Unexpected character \"%s\" (ASCII %d)', $chr, ord($chr)\n            );\n        }\n\n        $errorHandler->handleError(new Error($errorMsg, [\n            'startLine' => $token->line,\n            'endLine' => $token->line,\n            'startFilePos' => $token->pos,\n            'endFilePos' => $token->pos,\n        ]));\n    }\n\n    private function isUnterminatedComment(Token $token): bool {\n        return $token->is([\\T_COMMENT, \\T_DOC_COMMENT])\n            && substr($token->text, 0, 2) === '/*'\n            && substr($token->text, -2) !== '*/';\n    }\n\n    /**\n     * @param list<Token> $tokens\n     */\n    protected function postprocessTokens(array &$tokens, ErrorHandler $errorHandler): void {\n        // This function reports errors (bad characters and unterminated comments) in the token\n        // array, and performs certain canonicalizations:\n        //  * Use PHP 8.1 T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG and\n        //    T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG tokens used to disambiguate intersection types.\n        //  * Add a sentinel token with ID 0.\n\n        $numTokens = \\count($tokens);\n        if ($numTokens === 0) {\n            // Empty input edge case: Just add the sentinel token.\n            $tokens[] = new Token(0, \"\\0\", 1, 0);\n            return;\n        }\n\n        for ($i = 0; $i < $numTokens; $i++) {\n            $token = $tokens[$i];\n            if ($token->id === \\T_BAD_CHARACTER) {\n                $this->handleInvalidCharacter($token, $errorHandler);\n            }\n\n            if ($token->id === \\ord('&')) {\n                $next = $i + 1;\n                while (isset($tokens[$next]) && $tokens[$next]->id === \\T_WHITESPACE) {\n                    $next++;\n                }\n                $followedByVarOrVarArg = isset($tokens[$next]) &&\n                    $tokens[$next]->is([\\T_VARIABLE, \\T_ELLIPSIS]);\n                $token->id = $followedByVarOrVarArg\n                    ? \\T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG\n                    : \\T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG;\n            }\n        }\n\n        // Check for unterminated comment\n        $lastToken = $tokens[$numTokens - 1];\n        if ($this->isUnterminatedComment($lastToken)) {\n            $errorHandler->handleError(new Error('Unterminated comment', [\n                'startLine' => $lastToken->line,\n                'endLine' => $lastToken->getEndLine(),\n                'startFilePos' => $lastToken->pos,\n                'endFilePos' => $lastToken->getEndPos(),\n            ]));\n        }\n\n        // Add sentinel token.\n        $tokens[] = new Token(0, \"\\0\", $lastToken->getEndLine(), $lastToken->getEndPos());\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Modifiers.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\n/**\n * Modifiers used (as a bit mask) by various flags subnodes, for example on classes, functions,\n * properties and constants.\n */\nfinal class Modifiers {\n    public const PUBLIC    =  1;\n    public const PROTECTED =  2;\n    public const PRIVATE   =  4;\n    public const STATIC    =  8;\n    public const ABSTRACT  = 16;\n    public const FINAL     = 32;\n    public const READONLY  = 64;\n    public const PUBLIC_SET = 128;\n    public const PROTECTED_SET = 256;\n    public const PRIVATE_SET = 512;\n\n    public const VISIBILITY_MASK = self::PUBLIC | self::PROTECTED | self::PRIVATE;\n\n    public const VISIBILITY_SET_MASK = self::PUBLIC_SET | self::PROTECTED_SET | self::PRIVATE_SET;\n\n    private const TO_STRING_MAP = [\n        self::PUBLIC  => 'public',\n        self::PROTECTED => 'protected',\n        self::PRIVATE => 'private',\n        self::STATIC  => 'static',\n        self::ABSTRACT => 'abstract',\n        self::FINAL  => 'final',\n        self::READONLY  => 'readonly',\n        self::PUBLIC_SET => 'public(set)',\n        self::PROTECTED_SET => 'protected(set)',\n        self::PRIVATE_SET => 'private(set)',\n    ];\n\n    public static function toString(int $modifier): string {\n        if (!isset(self::TO_STRING_MAP[$modifier])) {\n            throw new \\InvalidArgumentException(\"Unknown modifier $modifier\");\n        }\n        return self::TO_STRING_MAP[$modifier];\n    }\n\n    private static function isValidModifier(int $modifier): bool {\n        $isPow2 = ($modifier & ($modifier - 1)) == 0 && $modifier != 0;\n        return $isPow2 && $modifier <= self::PRIVATE_SET;\n    }\n\n    /**\n     * @internal\n     */\n    public static function verifyClassModifier(int $a, int $b): void {\n        assert(self::isValidModifier($b));\n        if (($a & $b) != 0) {\n            throw new Error(\n                'Multiple ' . self::toString($b) . ' modifiers are not allowed');\n        }\n\n        if ($a & 48 && $b & 48) {\n            throw new Error('Cannot use the final modifier on an abstract class');\n        }\n    }\n\n    /**\n     * @internal\n     */\n    public static function verifyModifier(int $a, int $b): void {\n        assert(self::isValidModifier($b));\n        if (($a & Modifiers::VISIBILITY_MASK && $b & Modifiers::VISIBILITY_MASK) ||\n            ($a & Modifiers::VISIBILITY_SET_MASK && $b & Modifiers::VISIBILITY_SET_MASK)\n        ) {\n            throw new Error('Multiple access type modifiers are not allowed');\n        }\n\n        if (($a & $b) != 0) {\n            throw new Error(\n                'Multiple ' . self::toString($b) . ' modifiers are not allowed');\n        }\n\n        if ($a & 48 && $b & 48) {\n            throw new Error('Cannot use the final modifier on an abstract class member');\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NameContext.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Name\\FullyQualified;\nuse PhpParser\\Node\\Stmt;\n\nclass NameContext {\n    /** @var null|Name Current namespace */\n    protected ?Name $namespace;\n\n    /** @var Name[][] Map of format [aliasType => [aliasName => originalName]] */\n    protected array $aliases = [];\n\n    /** @var Name[][] Same as $aliases but preserving original case */\n    protected array $origAliases = [];\n\n    /** @var ErrorHandler Error handler */\n    protected ErrorHandler $errorHandler;\n\n    /**\n     * Create a name context.\n     *\n     * @param ErrorHandler $errorHandler Error handling used to report errors\n     */\n    public function __construct(ErrorHandler $errorHandler) {\n        $this->errorHandler = $errorHandler;\n    }\n\n    /**\n     * Start a new namespace.\n     *\n     * This also resets the alias table.\n     *\n     * @param Name|null $namespace Null is the global namespace\n     */\n    public function startNamespace(?Name $namespace = null): void {\n        $this->namespace = $namespace;\n        $this->origAliases = $this->aliases = [\n            Stmt\\Use_::TYPE_NORMAL   => [],\n            Stmt\\Use_::TYPE_FUNCTION => [],\n            Stmt\\Use_::TYPE_CONSTANT => [],\n        ];\n    }\n\n    /**\n     * Add an alias / import.\n     *\n     * @param Name $name Original name\n     * @param string $aliasName Aliased name\n     * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_*\n     * @param array<string, mixed> $errorAttrs Attributes to use to report an error\n     */\n    public function addAlias(Name $name, string $aliasName, int $type, array $errorAttrs = []): void {\n        // Constant names are case sensitive, everything else case insensitive\n        if ($type === Stmt\\Use_::TYPE_CONSTANT) {\n            $aliasLookupName = $aliasName;\n        } else {\n            $aliasLookupName = strtolower($aliasName);\n        }\n\n        if (isset($this->aliases[$type][$aliasLookupName])) {\n            $typeStringMap = [\n                Stmt\\Use_::TYPE_NORMAL   => '',\n                Stmt\\Use_::TYPE_FUNCTION => 'function ',\n                Stmt\\Use_::TYPE_CONSTANT => 'const ',\n            ];\n\n            $this->errorHandler->handleError(new Error(\n                sprintf(\n                    'Cannot use %s%s as %s because the name is already in use',\n                    $typeStringMap[$type], $name, $aliasName\n                ),\n                $errorAttrs\n            ));\n            return;\n        }\n\n        $this->aliases[$type][$aliasLookupName] = $name;\n        $this->origAliases[$type][$aliasName] = $name;\n    }\n\n    /**\n     * Get current namespace.\n     *\n     * @return null|Name Namespace (or null if global namespace)\n     */\n    public function getNamespace(): ?Name {\n        return $this->namespace;\n    }\n\n    /**\n     * Get resolved name.\n     *\n     * @param Name $name Name to resolve\n     * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_{FUNCTION|CONSTANT}\n     *\n     * @return null|Name Resolved name, or null if static resolution is not possible\n     */\n    public function getResolvedName(Name $name, int $type): ?Name {\n        // don't resolve special class names\n        if ($type === Stmt\\Use_::TYPE_NORMAL && $name->isSpecialClassName()) {\n            if (!$name->isUnqualified()) {\n                $this->errorHandler->handleError(new Error(\n                    sprintf(\"'\\\\%s' is an invalid class name\", $name->toString()),\n                    $name->getAttributes()\n                ));\n            }\n            return $name;\n        }\n\n        // fully qualified names are already resolved\n        if ($name->isFullyQualified()) {\n            return $name;\n        }\n\n        // Try to resolve aliases\n        if (null !== $resolvedName = $this->resolveAlias($name, $type)) {\n            return $resolvedName;\n        }\n\n        if ($type !== Stmt\\Use_::TYPE_NORMAL && $name->isUnqualified()) {\n            if (null === $this->namespace) {\n                // outside of a namespace unaliased unqualified is same as fully qualified\n                return new FullyQualified($name, $name->getAttributes());\n            }\n\n            // Cannot resolve statically\n            return null;\n        }\n\n        // if no alias exists prepend current namespace\n        return FullyQualified::concat($this->namespace, $name, $name->getAttributes());\n    }\n\n    /**\n     * Get resolved class name.\n     *\n     * @param Name $name Class ame to resolve\n     *\n     * @return Name Resolved name\n     */\n    public function getResolvedClassName(Name $name): Name {\n        return $this->getResolvedName($name, Stmt\\Use_::TYPE_NORMAL);\n    }\n\n    /**\n     * Get possible ways of writing a fully qualified name (e.g., by making use of aliases).\n     *\n     * @param string $name Fully-qualified name (without leading namespace separator)\n     * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_*\n     *\n     * @return Name[] Possible representations of the name\n     */\n    public function getPossibleNames(string $name, int $type): array {\n        $lcName = strtolower($name);\n\n        if ($type === Stmt\\Use_::TYPE_NORMAL) {\n            // self, parent and static must always be unqualified\n            if ($lcName === \"self\" || $lcName === \"parent\" || $lcName === \"static\") {\n                return [new Name($name)];\n            }\n        }\n\n        // Collect possible ways to write this name, starting with the fully-qualified name\n        $possibleNames = [new FullyQualified($name)];\n\n        if (null !== $nsRelativeName = $this->getNamespaceRelativeName($name, $lcName, $type)) {\n            // Make sure there is no alias that makes the normally namespace-relative name\n            // into something else\n            if (null === $this->resolveAlias($nsRelativeName, $type)) {\n                $possibleNames[] = $nsRelativeName;\n            }\n        }\n\n        // Check for relevant namespace use statements\n        foreach ($this->origAliases[Stmt\\Use_::TYPE_NORMAL] as $alias => $orig) {\n            $lcOrig = $orig->toLowerString();\n            if (0 === strpos($lcName, $lcOrig . '\\\\')) {\n                $possibleNames[] = new Name($alias . substr($name, strlen($lcOrig)));\n            }\n        }\n\n        // Check for relevant type-specific use statements\n        foreach ($this->origAliases[$type] as $alias => $orig) {\n            if ($type === Stmt\\Use_::TYPE_CONSTANT) {\n                // Constants are complicated-sensitive\n                $normalizedOrig = $this->normalizeConstName($orig->toString());\n                if ($normalizedOrig === $this->normalizeConstName($name)) {\n                    $possibleNames[] = new Name($alias);\n                }\n            } else {\n                // Everything else is case-insensitive\n                if ($orig->toLowerString() === $lcName) {\n                    $possibleNames[] = new Name($alias);\n                }\n            }\n        }\n\n        return $possibleNames;\n    }\n\n    /**\n     * Get shortest representation of this fully-qualified name.\n     *\n     * @param string $name Fully-qualified name (without leading namespace separator)\n     * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_*\n     *\n     * @return Name Shortest representation\n     */\n    public function getShortName(string $name, int $type): Name {\n        $possibleNames = $this->getPossibleNames($name, $type);\n\n        // Find shortest name\n        $shortestName = null;\n        $shortestLength = \\INF;\n        foreach ($possibleNames as $possibleName) {\n            $length = strlen($possibleName->toCodeString());\n            if ($length < $shortestLength) {\n                $shortestName = $possibleName;\n                $shortestLength = $length;\n            }\n        }\n\n        return $shortestName;\n    }\n\n    private function resolveAlias(Name $name, int $type): ?FullyQualified {\n        $firstPart = $name->getFirst();\n\n        if ($name->isQualified()) {\n            // resolve aliases for qualified names, always against class alias table\n            $checkName = strtolower($firstPart);\n            if (isset($this->aliases[Stmt\\Use_::TYPE_NORMAL][$checkName])) {\n                $alias = $this->aliases[Stmt\\Use_::TYPE_NORMAL][$checkName];\n                return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());\n            }\n        } elseif ($name->isUnqualified()) {\n            // constant aliases are case-sensitive, function aliases case-insensitive\n            $checkName = $type === Stmt\\Use_::TYPE_CONSTANT ? $firstPart : strtolower($firstPart);\n            if (isset($this->aliases[$type][$checkName])) {\n                // resolve unqualified aliases\n                return new FullyQualified($this->aliases[$type][$checkName], $name->getAttributes());\n            }\n        }\n\n        // No applicable aliases\n        return null;\n    }\n\n    private function getNamespaceRelativeName(string $name, string $lcName, int $type): ?Name {\n        if (null === $this->namespace) {\n            return new Name($name);\n        }\n\n        if ($type === Stmt\\Use_::TYPE_CONSTANT) {\n            // The constants true/false/null always resolve to the global symbols, even inside a\n            // namespace, so they may be used without qualification\n            if ($lcName === \"true\" || $lcName === \"false\" || $lcName === \"null\") {\n                return new Name($name);\n            }\n        }\n\n        $namespacePrefix = strtolower($this->namespace . '\\\\');\n        if (0 === strpos($lcName, $namespacePrefix)) {\n            return new Name(substr($name, strlen($namespacePrefix)));\n        }\n\n        return null;\n    }\n\n    private function normalizeConstName(string $name): string {\n        $nsSep = strrpos($name, '\\\\');\n        if (false === $nsSep) {\n            return $name;\n        }\n\n        // Constants have case-insensitive namespace and case-sensitive short-name\n        $ns = substr($name, 0, $nsSep);\n        $shortName = substr($name, $nsSep + 1);\n        return strtolower($ns) . '\\\\' . $shortName;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Arg.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass Arg extends NodeAbstract {\n    /** @var Identifier|null Parameter name (for named parameters) */\n    public ?Identifier $name;\n    /** @var Expr Value to pass */\n    public Expr $value;\n    /** @var bool Whether to pass by ref */\n    public bool $byRef;\n    /** @var bool Whether to unpack the argument */\n    public bool $unpack;\n\n    /**\n     * Constructs a function call argument node.\n     *\n     * @param Expr $value Value to pass\n     * @param bool $byRef Whether to pass by ref\n     * @param bool $unpack Whether to unpack the argument\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param Identifier|null $name Parameter name (for named parameters)\n     */\n    public function __construct(\n        Expr $value, bool $byRef = false, bool $unpack = false, array $attributes = [],\n        ?Identifier $name = null\n    ) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n        $this->value = $value;\n        $this->byRef = $byRef;\n        $this->unpack = $unpack;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'value', 'byRef', 'unpack'];\n    }\n\n    public function getType(): string {\n        return 'Arg';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/ArgPlaceholder.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\n/**\n * Represents the \"?\" argument placeholder of the partial function application syntax,\n * e.g. the \"?\" in \"foo(?)\". Like VariadicPlaceholder, it occurs in the argument list\n * of a call, in place of an ordinary Arg.\n */\nclass ArgPlaceholder extends NodeAbstract {\n    /** @var Identifier|null Parameter name (for named placeholders) */\n    public ?Identifier $name;\n\n    /**\n     * Create a \"?\" argument placeholder (partial function application syntax).\n     *\n     * @param Identifier|null $name Parameter name (for named placeholders)\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Identifier $name = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    public function getType(): string {\n        return 'ArgPlaceholder';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/ArrayItem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass ArrayItem extends NodeAbstract {\n    /** @var null|Expr Key */\n    public ?Expr $key;\n    /** @var Expr Value */\n    public Expr $value;\n    /** @var bool Whether to assign by reference */\n    public bool $byRef;\n    /** @var bool Whether to unpack the argument */\n    public bool $unpack;\n\n    /**\n     * Constructs an array item node.\n     *\n     * @param Expr $value Value\n     * @param null|Expr $key Key\n     * @param bool $byRef Whether to assign by reference\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $value, ?Expr $key = null, bool $byRef = false, array $attributes = [], bool $unpack = false) {\n        $this->attributes = $attributes;\n        $this->key = $key;\n        $this->value = $value;\n        $this->byRef = $byRef;\n        $this->unpack = $unpack;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['key', 'value', 'byRef', 'unpack'];\n    }\n\n    public function getType(): string {\n        return 'ArrayItem';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(ArrayItem::class, Expr\\ArrayItem::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Attribute.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass Attribute extends NodeAbstract {\n    /** @var Name Attribute name */\n    public Name $name;\n\n    /** @var list<Arg> Attribute arguments */\n    public array $args;\n\n    /**\n     * @param Node\\Name $name Attribute name\n     * @param list<Arg> $args Attribute arguments\n     * @param array<string, mixed> $attributes Additional node attributes\n     */\n    public function __construct(Name $name, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Attribute';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/AttributeGroup.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass AttributeGroup extends NodeAbstract {\n    /** @var Attribute[] Attributes */\n    public array $attrs;\n\n    /**\n     * @param Attribute[] $attrs PHP attributes\n     * @param array<string, mixed> $attributes Additional node attributes\n     */\n    public function __construct(array $attrs, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->attrs = $attrs;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrs'];\n    }\n\n    public function getType(): string {\n        return 'AttributeGroup';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/ClosureUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass ClosureUse extends NodeAbstract {\n    /** @var Expr\\Variable Variable to use */\n    public Expr\\Variable $var;\n    /** @var bool Whether to use by reference */\n    public bool $byRef;\n\n    /**\n     * Constructs a closure use node.\n     *\n     * @param Expr\\Variable $var Variable to use\n     * @param bool $byRef Whether to use by reference\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr\\Variable $var, bool $byRef = false, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->byRef = $byRef;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'byRef'];\n    }\n\n    public function getType(): string {\n        return 'ClosureUse';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(ClosureUse::class, Expr\\ClosureUse::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/ComplexType.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\n/**\n * This is a base class for complex types, including nullable types and union types.\n *\n * It does not provide any shared behavior and exists only for type-checking purposes.\n */\nabstract class ComplexType extends NodeAbstract {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Const_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass Const_ extends NodeAbstract {\n    /** @var Identifier Name */\n    public Identifier $name;\n    /** @var Expr Value */\n    public Expr $value;\n\n    /** @var Name|null Namespaced name (if using NameResolver) */\n    public ?Name $namespacedName;\n\n    /**\n     * Constructs a const node for use in class const and const statements.\n     *\n     * @param string|Identifier $name Name\n     * @param Expr $value Value\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, Expr $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'value'];\n    }\n\n    public function getType(): string {\n        return 'Const';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/DeclareItem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass DeclareItem extends NodeAbstract {\n    /** @var Node\\Identifier Key */\n    public Identifier $key;\n    /** @var Node\\Expr Value */\n    public Expr $value;\n\n    /**\n     * Constructs a declare key=>value pair node.\n     *\n     * @param string|Node\\Identifier $key Key\n     * @param Node\\Expr $value Value\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($key, Node\\Expr $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->key = \\is_string($key) ? new Node\\Identifier($key) : $key;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['key', 'value'];\n    }\n\n    public function getType(): string {\n        return 'DeclareItem';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(DeclareItem::class, Stmt\\DeclareDeclare::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayDimFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass ArrayDimFetch extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n    /** @var null|Expr Array index / dim */\n    public ?Expr $dim;\n\n    /**\n     * Constructs an array index fetch node.\n     *\n     * @param Expr $var Variable\n     * @param null|Expr $dim Array index / dim\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, ?Expr $dim = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->dim = $dim;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'dim'];\n    }\n\n    public function getType(): string {\n        return 'Expr_ArrayDimFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrayItem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nrequire __DIR__ . '/../ArrayItem.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\ArrayItem instead.\n     */\n    class ArrayItem extends \\PhpParser\\Node\\ArrayItem {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Array_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\ArrayItem;\nuse PhpParser\\Node\\Expr;\n\nclass Array_ extends Expr {\n    // For use in \"kind\" attribute\n    public const KIND_LONG = 1;  // array() syntax\n    public const KIND_SHORT = 2; // [] syntax\n\n    /** @var ArrayItem[] Items */\n    public array $items;\n\n    /**\n     * Constructs an array node.\n     *\n     * @param ArrayItem[] $items Items of the array\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $items = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->items = $items;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['items'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Array';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ArrowFunction.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\FunctionLike;\n\nclass ArrowFunction extends Expr implements FunctionLike {\n    /** @var bool Whether the closure is static */\n    public bool $static;\n\n    /** @var bool Whether to return by reference */\n    public bool $byRef;\n\n    /** @var Node\\Param[] */\n    public array $params = [];\n\n    /** @var null|Node\\Identifier|Node\\Name|Node\\ComplexType */\n    public ?Node $returnType;\n\n    /** @var Expr Expression body */\n    public Expr $expr;\n    /** @var Node\\AttributeGroup[] */\n    public array $attrGroups;\n\n    /**\n     * @param array{\n     *     expr: Expr,\n     *     static?: bool,\n     *     byRef?: bool,\n     *     params?: Node\\Param[],\n     *     returnType?: null|Node\\Identifier|Node\\Name|Node\\ComplexType,\n     *     attrGroups?: Node\\AttributeGroup[]\n     * } $subNodes Array of the following subnodes:\n     *             'expr'                  : Expression body\n     *             'static'     => false   : Whether the closure is static\n     *             'byRef'      => false   : Whether to return by reference\n     *             'params'     => array() : Parameters\n     *             'returnType' => null    : Return type\n     *             'attrGroups' => array() : PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $subNodes, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->static = $subNodes['static'] ?? false;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->params = $subNodes['params'] ?? [];\n        $this->returnType = $subNodes['returnType'] ?? null;\n        $this->expr = $subNodes['expr'];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'static', 'byRef', 'params', 'returnType', 'expr'];\n    }\n\n    public function returnsByRef(): bool {\n        return $this->byRef;\n    }\n\n    public function getParams(): array {\n        return $this->params;\n    }\n\n    public function getReturnType() {\n        return $this->returnType;\n    }\n\n    public function getAttrGroups(): array {\n        return $this->attrGroups;\n    }\n\n    /**\n     * @return Node\\Stmt\\Return_[]\n     */\n    public function getStmts(): array {\n        return [new Node\\Stmt\\Return_($this->expr)];\n    }\n\n    public function getType(): string {\n        return 'Expr_ArrowFunction';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Assign.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Assign extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs an assignment node.\n     *\n     * @param Expr $var Variable\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Assign';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseAnd.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass BitwiseAnd extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_BitwiseAnd';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseOr.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass BitwiseOr extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_BitwiseOr';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/BitwiseXor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass BitwiseXor extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_BitwiseXor';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Coalesce.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Coalesce extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Coalesce';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Concat.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Concat extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Concat';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Div.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Div extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Div';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Minus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Minus extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Minus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mod.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Mod extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Mod';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Mul.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Mul extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Mul';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Plus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Plus extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Plus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/Pow.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass Pow extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_Pow';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftLeft.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass ShiftLeft extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_ShiftLeft';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp/ShiftRight.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\AssignOp;\n\nuse PhpParser\\Node\\Expr\\AssignOp;\n\nclass ShiftRight extends AssignOp {\n    public function getType(): string {\n        return 'Expr_AssignOp_ShiftRight';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignOp.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nabstract class AssignOp extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a compound assignment operation node.\n     *\n     * @param Expr $var Variable\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'expr'];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/AssignRef.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass AssignRef extends Expr {\n    /** @var Expr Variable reference is assigned to */\n    public Expr $var;\n    /** @var Expr Variable which is referenced */\n    public Expr $expr;\n\n    /**\n     * Constructs an assignment node.\n     *\n     * @param Expr $var Variable\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_AssignRef';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseAnd.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass BitwiseAnd extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '&';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_BitwiseAnd';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseOr.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass BitwiseOr extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '|';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_BitwiseOr';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BitwiseXor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass BitwiseXor extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '^';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_BitwiseXor';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanAnd.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass BooleanAnd extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '&&';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_BooleanAnd';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/BooleanOr.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass BooleanOr extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '||';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_BooleanOr';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Coalesce.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Coalesce extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '??';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Coalesce';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Concat.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Concat extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '.';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Concat';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Div.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Div extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '/';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Div';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Equal.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Equal extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '==';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Equal';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Greater.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Greater extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '>';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Greater';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/GreaterOrEqual.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass GreaterOrEqual extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '>=';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_GreaterOrEqual';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Identical.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Identical extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '===';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Identical';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalAnd.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass LogicalAnd extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return 'and';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_LogicalAnd';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalOr.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass LogicalOr extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return 'or';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_LogicalOr';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/LogicalXor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass LogicalXor extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return 'xor';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_LogicalXor';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Minus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Minus extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '-';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Minus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mod.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Mod extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '%';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Mod';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Mul.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Mul extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '*';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Mul';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotEqual.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass NotEqual extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '!=';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_NotEqual';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/NotIdentical.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass NotIdentical extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '!==';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_NotIdentical';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pipe.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Pipe extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '|>';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Pipe';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Plus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Plus extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '+';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Plus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Pow.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Pow extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '**';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Pow';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftLeft.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass ShiftLeft extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '<<';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_ShiftLeft';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/ShiftRight.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass ShiftRight extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '>>';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_ShiftRight';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Smaller.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Smaller extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '<';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Smaller';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/SmallerOrEqual.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass SmallerOrEqual extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '<=';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_SmallerOrEqual';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp/Spaceship.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\BinaryOp;\n\nuse PhpParser\\Node\\Expr\\BinaryOp;\n\nclass Spaceship extends BinaryOp {\n    public function getOperatorSigil(): string {\n        return '<=>';\n    }\n\n    public function getType(): string {\n        return 'Expr_BinaryOp_Spaceship';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BinaryOp.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nabstract class BinaryOp extends Expr {\n    /** @var Expr The left hand side expression */\n    public Expr $left;\n    /** @var Expr The right hand side expression */\n    public Expr $right;\n\n    /**\n     * Constructs a binary operator node.\n     *\n     * @param Expr $left The left hand side expression\n     * @param Expr $right The right hand side expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $left, Expr $right, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->left = $left;\n        $this->right = $right;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['left', 'right'];\n    }\n\n    /**\n     * Get the operator sigil for this binary operation.\n     *\n     * In the case there are multiple possible sigils for an operator, this method does not\n     * necessarily return the one used in the parsed code.\n     */\n    abstract public function getOperatorSigil(): string;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BitwiseNot.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass BitwiseNot extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a bitwise not node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_BitwiseNot';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/BooleanNot.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass BooleanNot extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a boolean not node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_BooleanNot';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/CallLike.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\ArgPlaceholder;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\VariadicPlaceholder;\n\nabstract class CallLike extends Expr {\n    /**\n     * Return raw arguments, which may be actual Args, VariadicPlaceholders for first-class\n     * callables, or ArgPlaceholders for partial function application.\n     *\n     * @return array<Arg|VariadicPlaceholder|ArgPlaceholder>\n     */\n    abstract public function getRawArgs(): array;\n\n    /**\n     * Returns whether this call expression is actually a first class callable.\n     */\n    public function isFirstClassCallable(): bool {\n        $rawArgs = $this->getRawArgs();\n        return count($rawArgs) === 1 && current($rawArgs) instanceof VariadicPlaceholder;\n    }\n\n    /**\n     * Returns whether this call expression is a partial function application, i.e. whether its\n     * argument list contains one or more \"?\" placeholders or a \"...\" placeholder. First-class\n     * callables are a special case of partial function application, so this also returns true\n     * for them.\n     */\n    public function isPartialFunctionApplication(): bool {\n        foreach ($this->getRawArgs() as $arg) {\n            if ($arg instanceof VariadicPlaceholder || $arg instanceof ArgPlaceholder) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Assert that this is not a partial function application (which includes first-class\n     * callables) and return only ordinary Args.\n     *\n     * @return Arg[]\n     */\n    public function getArgs(): array {\n        assert(!$this->isPartialFunctionApplication());\n        return $this->getRawArgs();\n    }\n\n    /**\n     * Retrieves a specific argument from the raw arguments.\n     *\n     * Returns the named argument that matches the given `$name`, or the\n     * positional (unnamed) argument that exists at the given `$position`.\n     * Returns `null` if no match is found, or when a \"...\" placeholder is\n     * encountered, as argument positions are no longer known past that point.\n     * A \"?\" placeholder occupies its argument position, but is never returned,\n     * as it is not an actual argument.\n     */\n    public function getArg(string $name, int $position): ?Arg {\n        foreach ($this->getRawArgs() as $i => $arg) {\n            if ($arg instanceof VariadicPlaceholder) {\n                return null;\n            }\n            if ($arg instanceof ArgPlaceholder || $arg->unpack) {\n                continue;\n            }\n            if (\n                ($arg->name !== null && $arg->name->toString() === $name)\n                || ($arg->name === null && $i === $position)\n            ) {\n                return $arg;\n            }\n        }\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Array_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Array_ extends Cast {\n    public function getType(): string {\n        return 'Expr_Cast_Array';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Bool_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Bool_ extends Cast {\n    // For use in \"kind\" attribute\n    public const KIND_BOOL = 1; // \"bool\" syntax\n    public const KIND_BOOLEAN = 2; // \"boolean\" syntax\n\n    public function getType(): string {\n        return 'Expr_Cast_Bool';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Double.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Double extends Cast {\n    // For use in \"kind\" attribute\n    public const KIND_DOUBLE = 1; // \"double\" syntax\n    public const KIND_FLOAT = 2;  // \"float\" syntax\n    public const KIND_REAL = 3; // \"real\" syntax\n\n    public function getType(): string {\n        return 'Expr_Cast_Double';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Int_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Int_ extends Cast {\n    // For use in \"kind\" attribute\n    public const KIND_INT = 1; // \"int\" syntax\n    public const KIND_INTEGER = 2; // \"integer\" syntax\n\n    public function getType(): string {\n        return 'Expr_Cast_Int';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Object_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Object_ extends Cast {\n    public function getType(): string {\n        return 'Expr_Cast_Object';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/String_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass String_ extends Cast {\n    // For use in \"kind\" attribute\n    public const KIND_STRING = 1; // \"string\" syntax\n    public const KIND_BINARY = 2; // \"binary\" syntax\n\n    public function getType(): string {\n        return 'Expr_Cast_String';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Unset_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Unset_ extends Cast {\n    public function getType(): string {\n        return 'Expr_Cast_Unset';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast/Void_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr\\Cast;\n\nuse PhpParser\\Node\\Expr\\Cast;\n\nclass Void_ extends Cast {\n    public function getType(): string {\n        return 'Expr_Cast_Void';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Cast.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nabstract class Cast extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a cast node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClassConstFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\n\nclass ClassConstFetch extends Expr {\n    /** @var Name|Expr Class name */\n    public Node $class;\n    /** @var Identifier|Expr|Error Constant name */\n    public Node $name;\n\n    /**\n     * Constructs a class const fetch node.\n     *\n     * @param Name|Expr $class Class name\n     * @param string|Identifier|Expr|Error $name Constant name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $class, $name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->class = $class;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['class', 'name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_ClassConstFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Clone_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Clone_ extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a clone node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Clone';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Closure.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\ClosureUse;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\FunctionLike;\n\nclass Closure extends Expr implements FunctionLike {\n    /** @var bool Whether the closure is static */\n    public bool $static;\n    /** @var bool Whether to return by reference */\n    public bool $byRef;\n    /** @var Node\\Param[] Parameters */\n    public array $params;\n    /** @var ClosureUse[] use()s */\n    public array $uses;\n    /** @var null|Node\\Identifier|Node\\Name|Node\\ComplexType Return type */\n    public ?Node $returnType;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /**\n     * Constructs a lambda function node.\n     *\n     * @param array{\n     *     static?: bool,\n     *     byRef?: bool,\n     *     params?: Node\\Param[],\n     *     uses?: ClosureUse[],\n     *     returnType?: null|Node\\Identifier|Node\\Name|Node\\ComplexType,\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'static'     => false  : Whether the closure is static\n     *             'byRef'      => false  : Whether to return by reference\n     *             'params'     => array(): Parameters\n     *             'uses'       => array(): use()s\n     *             'returnType' => null   : Return type\n     *             'stmts'      => array(): Statements\n     *             'attrGroups' => array(): PHP attributes groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->static = $subNodes['static'] ?? false;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->params = $subNodes['params'] ?? [];\n        $this->uses = $subNodes['uses'] ?? [];\n        $this->returnType = $subNodes['returnType'] ?? null;\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'static', 'byRef', 'params', 'uses', 'returnType', 'stmts'];\n    }\n\n    public function returnsByRef(): bool {\n        return $this->byRef;\n    }\n\n    public function getParams(): array {\n        return $this->params;\n    }\n\n    public function getReturnType() {\n        return $this->returnType;\n    }\n\n    /** @return Node\\Stmt[] */\n    public function getStmts(): array {\n        return $this->stmts;\n    }\n\n    public function getAttrGroups(): array {\n        return $this->attrGroups;\n    }\n\n    public function getType(): string {\n        return 'Expr_Closure';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ClosureUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nrequire __DIR__ . '/../ClosureUse.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\ClosureUse instead.\n     */\n    class ClosureUse extends \\PhpParser\\Node\\ClosureUse {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ConstFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\n\nclass ConstFetch extends Expr {\n    /** @var Name Constant name */\n    public Name $name;\n\n    /**\n     * Constructs a const fetch node.\n     *\n     * @param Name $name Constant name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Name $name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_ConstFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Empty_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Empty_ extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs an empty() node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Empty';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Error.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\n/**\n * Error node used during parsing with error recovery.\n *\n * An error node may be placed at a position where an expression is required, but an error occurred.\n * Error nodes will not be present if the parser is run in throwOnError mode (the default).\n */\nclass Error extends Expr {\n    /**\n     * Constructs an error node.\n     *\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $attributes = []) {\n        $this->attributes = $attributes;\n    }\n\n    public function getSubNodeNames(): array {\n        return [];\n    }\n\n    public function getType(): string {\n        return 'Expr_Error';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ErrorSuppress.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass ErrorSuppress extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs an error suppress node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_ErrorSuppress';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Eval_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Eval_ extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs an eval() node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Eval';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Exit_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Exit_ extends Expr {\n    /* For use in \"kind\" attribute */\n    public const KIND_EXIT = 1;\n    public const KIND_DIE = 2;\n\n    /** @var null|Expr Expression */\n    public ?Expr $expr;\n\n    /**\n     * Constructs an exit() node.\n     *\n     * @param null|Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Expr $expr = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Exit';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/FuncCall.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\n\nclass FuncCall extends CallLike {\n    /** @var Node\\Name|Expr Function name */\n    public Node $name;\n    /** @var array<Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder> Arguments */\n    public array $args;\n\n    /**\n     * Constructs a function call node.\n     *\n     * @param Node\\Name|Expr $name Function name\n     * @param array<Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder> $args Arguments\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $name, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Expr_FuncCall';\n    }\n\n    public function getRawArgs(): array {\n        return $this->args;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Include_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Include_ extends Expr {\n    public const TYPE_INCLUDE      = 1;\n    public const TYPE_INCLUDE_ONCE = 2;\n    public const TYPE_REQUIRE      = 3;\n    public const TYPE_REQUIRE_ONCE = 4;\n\n    /** @var Expr Expression */\n    public Expr $expr;\n    /** @var int Type of include */\n    public int $type;\n\n    /**\n     * Constructs an include node.\n     *\n     * @param Expr $expr Expression\n     * @param int $type Type of include\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, int $type, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n        $this->type = $type;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr', 'type'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Include';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Instanceof_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\n\nclass Instanceof_ extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n    /** @var Name|Expr Class name */\n    public Node $class;\n\n    /**\n     * Constructs an instanceof check node.\n     *\n     * @param Expr $expr Expression\n     * @param Name|Expr $class Class name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, Node $class, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n        $this->class = $class;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr', 'class'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Instanceof';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Isset_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Isset_ extends Expr {\n    /** @var Expr[] Variables */\n    public array $vars;\n\n    /**\n     * Constructs an array node.\n     *\n     * @param Expr[] $vars Variables\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $vars, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->vars = $vars;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['vars'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Isset';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/List_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\ArrayItem;\nuse PhpParser\\Node\\Expr;\n\nclass List_ extends Expr {\n    // For use in \"kind\" attribute\n    public const KIND_LIST = 1; // list() syntax\n    public const KIND_ARRAY = 2; // [] syntax\n\n    /** @var (ArrayItem|null)[] List of items to assign to */\n    public array $items;\n\n    /**\n     * Constructs a list() destructuring node.\n     *\n     * @param (ArrayItem|null)[] $items List of items to assign to\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $items, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->items = $items;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['items'];\n    }\n\n    public function getType(): string {\n        return 'Expr_List';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Match_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\MatchArm;\n\nclass Match_ extends Node\\Expr {\n    /** @var Node\\Expr Condition */\n    public Node\\Expr $cond;\n    /** @var MatchArm[] */\n    public array $arms;\n\n    /**\n     * @param Node\\Expr $cond Condition\n     * @param MatchArm[] $arms\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $arms = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->arms = $arms;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'arms'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Match';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/MethodCall.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\ArgPlaceholder;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\VariadicPlaceholder;\n\nclass MethodCall extends CallLike {\n    /** @var Expr Variable holding object */\n    public Expr $var;\n    /** @var Identifier|Expr Method name */\n    public Node $name;\n    /** @var array<Arg|VariadicPlaceholder|ArgPlaceholder> Arguments */\n    public array $args;\n\n    /**\n     * Constructs a function call node.\n     *\n     * @param Expr $var Variable holding object\n     * @param string|Identifier|Expr $name Method name\n     * @param array<Arg|VariadicPlaceholder|ArgPlaceholder> $args Arguments\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'name', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Expr_MethodCall';\n    }\n\n    public function getRawArgs(): array {\n        return $this->args;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/New_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\ArgPlaceholder;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\VariadicPlaceholder;\n\nclass New_ extends CallLike {\n    /** @var Node\\Name|Expr|Node\\Stmt\\Class_ Class name */\n    public Node $class;\n    /** @var array<Arg|VariadicPlaceholder|ArgPlaceholder> Arguments */\n    public array $args;\n\n    /**\n     * Constructs a function call node.\n     *\n     * @param Node\\Name|Expr|Node\\Stmt\\Class_ $class Class name (or class node for anonymous classes)\n     * @param array<Arg|VariadicPlaceholder|ArgPlaceholder> $args Arguments\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $class, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->class = $class;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['class', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Expr_New';\n    }\n\n    public function getRawArgs(): array {\n        return $this->args;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafeMethodCall.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\ArgPlaceholder;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\VariadicPlaceholder;\n\nclass NullsafeMethodCall extends CallLike {\n    /** @var Expr Variable holding object */\n    public Expr $var;\n    /** @var Identifier|Expr Method name */\n    public Node $name;\n    /** @var array<Arg|VariadicPlaceholder|ArgPlaceholder> Arguments */\n    public array $args;\n\n    /**\n     * Constructs a nullsafe method call node.\n     *\n     * @param Expr $var Variable holding object\n     * @param string|Identifier|Expr $name Method name\n     * @param array<Arg|VariadicPlaceholder|ArgPlaceholder> $args Arguments\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'name', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Expr_NullsafeMethodCall';\n    }\n\n    public function getRawArgs(): array {\n        return $this->args;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/NullsafePropertyFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\n\nclass NullsafePropertyFetch extends Expr {\n    /** @var Expr Variable holding object */\n    public Expr $var;\n    /** @var Identifier|Expr Property name */\n    public Node $name;\n\n    /**\n     * Constructs a nullsafe property fetch node.\n     *\n     * @param Expr $var Variable holding object\n     * @param string|Identifier|Expr $name Property name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, $name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_NullsafePropertyFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostDec.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass PostDec extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n\n    /**\n     * Constructs a post decrement node.\n     *\n     * @param Expr $var Variable\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var'];\n    }\n\n    public function getType(): string {\n        return 'Expr_PostDec';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PostInc.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass PostInc extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n\n    /**\n     * Constructs a post increment node.\n     *\n     * @param Expr $var Variable\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var'];\n    }\n\n    public function getType(): string {\n        return 'Expr_PostInc';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreDec.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass PreDec extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n\n    /**\n     * Constructs a pre decrement node.\n     *\n     * @param Expr $var Variable\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var'];\n    }\n\n    public function getType(): string {\n        return 'Expr_PreDec';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PreInc.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass PreInc extends Expr {\n    /** @var Expr Variable */\n    public Expr $var;\n\n    /**\n     * Constructs a pre increment node.\n     *\n     * @param Expr $var Variable\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var'];\n    }\n\n    public function getType(): string {\n        return 'Expr_PreInc';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Print_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Print_ extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs an print() node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Print';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/PropertyFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\n\nclass PropertyFetch extends Expr {\n    /** @var Expr Variable holding object */\n    public Expr $var;\n    /** @var Identifier|Expr Property name */\n    public Node $name;\n\n    /**\n     * Constructs a function call node.\n     *\n     * @param Expr $var Variable holding object\n     * @param string|Identifier|Expr $name Property name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $var, $name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_PropertyFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/ShellExec.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\InterpolatedStringPart;\n\nclass ShellExec extends Expr {\n    /** @var (Expr|InterpolatedStringPart)[] Interpolated string array */\n    public array $parts;\n\n    /**\n     * Constructs a shell exec (backtick) node.\n     *\n     * @param (Expr|InterpolatedStringPart)[] $parts Interpolated string array\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $parts, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->parts = $parts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['parts'];\n    }\n\n    public function getType(): string {\n        return 'Expr_ShellExec';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticCall.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\ArgPlaceholder;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\VariadicPlaceholder;\n\nclass StaticCall extends CallLike {\n    /** @var Node\\Name|Expr Class name */\n    public Node $class;\n    /** @var Identifier|Expr Method name */\n    public Node $name;\n    /** @var array<Arg|VariadicPlaceholder|ArgPlaceholder> Arguments */\n    public array $args;\n\n    /**\n     * Constructs a static method call node.\n     *\n     * @param Node\\Name|Expr $class Class name\n     * @param string|Identifier|Expr $name Method name\n     * @param array<Arg|VariadicPlaceholder|ArgPlaceholder> $args Arguments\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $class, $name, array $args = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->class = $class;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n        $this->args = $args;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['class', 'name', 'args'];\n    }\n\n    public function getType(): string {\n        return 'Expr_StaticCall';\n    }\n\n    public function getRawArgs(): array {\n        return $this->args;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/StaticPropertyFetch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\VarLikeIdentifier;\n\nclass StaticPropertyFetch extends Expr {\n    /** @var Name|Expr Class name */\n    public Node $class;\n    /** @var VarLikeIdentifier|Expr Property name */\n    public Node $name;\n\n    /**\n     * Constructs a static property fetch node.\n     *\n     * @param Name|Expr $class Class name\n     * @param string|VarLikeIdentifier|Expr $name Property name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $class, $name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->class = $class;\n        $this->name = \\is_string($name) ? new VarLikeIdentifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['class', 'name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_StaticPropertyFetch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Ternary.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Ternary extends Expr {\n    /** @var Expr Condition */\n    public Expr $cond;\n    /** @var null|Expr Expression for true */\n    public ?Expr $if;\n    /** @var Expr Expression for false */\n    public Expr $else;\n\n    /**\n     * Constructs a ternary operator node.\n     *\n     * @param Expr $cond Condition\n     * @param null|Expr $if Expression for true\n     * @param Expr $else Expression for false\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $cond, ?Expr $if, Expr $else, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->if = $if;\n        $this->else = $else;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'if', 'else'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Ternary';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Throw_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node;\n\nclass Throw_ extends Node\\Expr {\n    /** @var Node\\Expr Expression */\n    public Node\\Expr $expr;\n\n    /**\n     * Constructs a throw expression node.\n     *\n     * @param Node\\Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Throw';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryMinus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass UnaryMinus extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a unary minus node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_UnaryMinus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/UnaryPlus.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass UnaryPlus extends Expr {\n    /** @var Expr Expression */\n    public Expr $expr;\n\n    /**\n     * Constructs a unary plus node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_UnaryPlus';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Variable.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Variable extends Expr {\n    /** @var string|Expr Name */\n    public $name;\n\n    /**\n     * Constructs a variable node.\n     *\n     * @param string|Expr $name Name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Variable';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/YieldFrom.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass YieldFrom extends Expr {\n    /** @var Expr Expression to yield from */\n    public Expr $expr;\n\n    /**\n     * Constructs an \"yield from\" node.\n     *\n     * @param Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Expr_YieldFrom';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr/Yield_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Expr;\n\nuse PhpParser\\Node\\Expr;\n\nclass Yield_ extends Expr {\n    /** @var null|Expr Key expression */\n    public ?Expr $key;\n    /** @var null|Expr Value expression */\n    public ?Expr $value;\n\n    /**\n     * Constructs a yield expression node.\n     *\n     * @param null|Expr $value Value expression\n     * @param null|Expr $key Key expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Expr $value = null, ?Expr $key = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->key = $key;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['key', 'value'];\n    }\n\n    public function getType(): string {\n        return 'Expr_Yield';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Expr.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nabstract class Expr extends NodeAbstract {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/FunctionLike.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\n\ninterface FunctionLike extends Node {\n    /**\n     * Whether to return by reference\n     */\n    public function returnsByRef(): bool;\n\n    /**\n     * List of parameters\n     *\n     * @return Param[]\n     */\n    public function getParams(): array;\n\n    /**\n     * Get the declared return type or null\n     *\n     * @return null|Identifier|Name|ComplexType\n     */\n    public function getReturnType();\n\n    /**\n     * The function body\n     *\n     * @return Stmt[]|null\n     */\n    public function getStmts(): ?array;\n\n    /**\n     * Get PHP attribute groups.\n     *\n     * @return AttributeGroup[]\n     */\n    public function getAttrGroups(): array;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Identifier.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\n/**\n * Represents a non-namespaced name. Namespaced names are represented using Name nodes.\n */\nclass Identifier extends NodeAbstract {\n    /**\n     * @psalm-var non-empty-string\n     * @var string Identifier as string\n     */\n    public string $name;\n\n    /** @var array<string, bool> */\n    private static array $specialClassNames = [\n        'self'   => true,\n        'parent' => true,\n        'static' => true,\n    ];\n\n    /**\n     * Constructs an identifier node.\n     *\n     * @param string $name Identifier as string\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(string $name, array $attributes = []) {\n        if ($name === '') {\n            throw new \\InvalidArgumentException('Identifier name cannot be empty');\n        }\n\n        $this->attributes = $attributes;\n        $this->name = $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    /**\n     * Get identifier as string.\n     *\n     * @psalm-return non-empty-string\n     * @return string Identifier as string.\n     */\n    public function toString(): string {\n        return $this->name;\n    }\n\n    /**\n     * Get lowercased identifier as string.\n     *\n     * @psalm-return non-empty-string&lowercase-string\n     * @return string Lowercased identifier as string\n     */\n    public function toLowerString(): string {\n        return strtolower($this->name);\n    }\n\n    /**\n     * Checks whether the identifier is a special class name (self, parent or static).\n     *\n     * @return bool Whether identifier is a special class name\n     */\n    public function isSpecialClassName(): bool {\n        return isset(self::$specialClassNames[strtolower($this->name)]);\n    }\n\n    /**\n     * Get identifier as string.\n     *\n     * @psalm-return non-empty-string\n     * @return string Identifier as string\n     */\n    public function __toString(): string {\n        return $this->name;\n    }\n\n    public function getType(): string {\n        return 'Identifier';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/InterpolatedStringPart.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass InterpolatedStringPart extends NodeAbstract {\n    /** @var string String value */\n    public string $value;\n\n    /**\n     * Constructs a node representing a string part of an interpolated string.\n     *\n     * @param string $value String value\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(string $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['value'];\n    }\n\n    public function getType(): string {\n        return 'InterpolatedStringPart';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(InterpolatedStringPart::class, Scalar\\EncapsedStringPart::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/IntersectionType.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nclass IntersectionType extends ComplexType {\n    /** @var (Identifier|Name)[] Types */\n    public array $types;\n\n    /**\n     * Constructs an intersection type.\n     *\n     * @param (Identifier|Name)[] $types Types\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $types, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->types = $types;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['types'];\n    }\n\n    public function getType(): string {\n        return 'IntersectionType';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/MatchArm.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass MatchArm extends NodeAbstract {\n    /** @var null|list<Node\\Expr> */\n    public ?array $conds;\n    public Expr $body;\n\n    /**\n     * @param null|list<Node\\Expr> $conds\n     */\n    public function __construct(?array $conds, Node\\Expr $body, array $attributes = []) {\n        $this->conds = $conds;\n        $this->body = $body;\n        $this->attributes = $attributes;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['conds', 'body'];\n    }\n\n    public function getType(): string {\n        return 'MatchArm';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Name/FullyQualified.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Name;\n\nclass FullyQualified extends \\PhpParser\\Node\\Name {\n    /**\n     * Checks whether the name is unqualified. (E.g. Name)\n     *\n     * @return bool Whether the name is unqualified\n     */\n    public function isUnqualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is qualified. (E.g. Name\\Name)\n     *\n     * @return bool Whether the name is qualified\n     */\n    public function isQualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is fully qualified. (E.g. \\Name)\n     *\n     * @return bool Whether the name is fully qualified\n     */\n    public function isFullyQualified(): bool {\n        return true;\n    }\n\n    /**\n     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\\Name)\n     *\n     * @return bool Whether the name is relative\n     */\n    public function isRelative(): bool {\n        return false;\n    }\n\n    public function toCodeString(): string {\n        return '\\\\' . $this->toString();\n    }\n\n    public function getType(): string {\n        return 'Name_FullyQualified';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Name/Relative.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Name;\n\nclass Relative extends \\PhpParser\\Node\\Name {\n    /**\n     * Checks whether the name is unqualified. (E.g. Name)\n     *\n     * @return bool Whether the name is unqualified\n     */\n    public function isUnqualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is qualified. (E.g. Name\\Name)\n     *\n     * @return bool Whether the name is qualified\n     */\n    public function isQualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is fully qualified. (E.g. \\Name)\n     *\n     * @return bool Whether the name is fully qualified\n     */\n    public function isFullyQualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\\Name)\n     *\n     * @return bool Whether the name is relative\n     */\n    public function isRelative(): bool {\n        return true;\n    }\n\n    public function toCodeString(): string {\n        return 'namespace\\\\' . $this->toString();\n    }\n\n    public function getType(): string {\n        return 'Name_Relative';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Name.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nclass Name extends NodeAbstract {\n    /**\n     * @psalm-var non-empty-string\n     * @var string Name as string\n     */\n    public string $name;\n\n    /** @var array<string, bool> */\n    private static array $specialClassNames = [\n        'self'   => true,\n        'parent' => true,\n        'static' => true,\n    ];\n\n    /**\n     * Constructs a name node.\n     *\n     * @param string|string[]|self $name Name as string, part array or Name instance (copy ctor)\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    final public function __construct($name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = self::prepareName($name);\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    /**\n     * Get parts of name (split by the namespace separator).\n     *\n     * @psalm-return non-empty-list<string>\n     * @return string[] Parts of name\n     */\n    public function getParts(): array {\n        return \\explode('\\\\', $this->name);\n    }\n\n    /**\n     * Gets the first part of the name, i.e. everything before the first namespace separator.\n     *\n     * @return string First part of the name\n     */\n    public function getFirst(): string {\n        if (false !== $pos = \\strpos($this->name, '\\\\')) {\n            return \\substr($this->name, 0, $pos);\n        }\n        return $this->name;\n    }\n\n    /**\n     * Gets the last part of the name, i.e. everything after the last namespace separator.\n     *\n     * @return string Last part of the name\n     */\n    public function getLast(): string {\n        if (false !== $pos = \\strrpos($this->name, '\\\\')) {\n            return \\substr($this->name, $pos + 1);\n        }\n        return $this->name;\n    }\n\n    /**\n     * Checks whether the name is unqualified. (E.g. Name)\n     *\n     * @return bool Whether the name is unqualified\n     */\n    public function isUnqualified(): bool {\n        return false === \\strpos($this->name, '\\\\');\n    }\n\n    /**\n     * Checks whether the name is qualified. (E.g. Name\\Name)\n     *\n     * @return bool Whether the name is qualified\n     */\n    public function isQualified(): bool {\n        return false !== \\strpos($this->name, '\\\\');\n    }\n\n    /**\n     * Checks whether the name is fully qualified. (E.g. \\Name)\n     *\n     * @return bool Whether the name is fully qualified\n     */\n    public function isFullyQualified(): bool {\n        return false;\n    }\n\n    /**\n     * Checks whether the name is explicitly relative to the current namespace. (E.g. namespace\\Name)\n     *\n     * @return bool Whether the name is relative\n     */\n    public function isRelative(): bool {\n        return false;\n    }\n\n    /**\n     * Returns a string representation of the name itself, without taking the name type into\n     * account (e.g., not including a leading backslash for fully qualified names).\n     *\n     * @psalm-return non-empty-string\n     * @return string String representation\n     */\n    public function toString(): string {\n        return $this->name;\n    }\n\n    /**\n     * Returns a string representation of the name as it would occur in code (e.g., including\n     * leading backslash for fully qualified names.\n     *\n     * @psalm-return non-empty-string\n     * @return string String representation\n     */\n    public function toCodeString(): string {\n        return $this->toString();\n    }\n\n    /**\n     * Returns lowercased string representation of the name, without taking the name type into\n     * account (e.g., no leading backslash for fully qualified names).\n     *\n     * @psalm-return non-empty-string&lowercase-string\n     * @return string Lowercased string representation\n     */\n    public function toLowerString(): string {\n        return strtolower($this->name);\n    }\n\n    /**\n     * Checks whether the identifier is a special class name (self, parent or static).\n     *\n     * @return bool Whether identifier is a special class name\n     */\n    public function isSpecialClassName(): bool {\n        return isset(self::$specialClassNames[strtolower($this->name)]);\n    }\n\n    /**\n     * Returns a string representation of the name by imploding the namespace parts with the\n     * namespace separator.\n     *\n     * @psalm-return non-empty-string\n     * @return string String representation\n     */\n    public function __toString(): string {\n        return $this->name;\n    }\n\n    /**\n     * Gets a slice of a name (similar to array_slice).\n     *\n     * This method returns a new instance of the same type as the original and with the same\n     * attributes.\n     *\n     * If the slice is empty, null is returned. The null value will be correctly handled in\n     * concatenations using concat().\n     *\n     * Offset and length have the same meaning as in array_slice().\n     *\n     * @param int $offset Offset to start the slice at (may be negative)\n     * @param int|null $length Length of the slice (may be negative)\n     *\n     * @return static|null Sliced name\n     */\n    public function slice(int $offset, ?int $length = null) {\n        if ($offset === 1 && $length === null) {\n            // Short-circuit the common case.\n            if (false !== $pos = \\strpos($this->name, '\\\\')) {\n                return new static(\\substr($this->name, $pos + 1));\n            }\n            return null;\n        }\n\n        $parts = \\explode('\\\\', $this->name);\n        $numParts = \\count($parts);\n\n        $realOffset = $offset < 0 ? $offset + $numParts : $offset;\n        if ($realOffset < 0 || $realOffset > $numParts) {\n            throw new \\OutOfBoundsException(sprintf('Offset %d is out of bounds', $offset));\n        }\n\n        if (null === $length) {\n            $realLength = $numParts - $realOffset;\n        } else {\n            $realLength = $length < 0 ? $length + $numParts - $realOffset : $length;\n            if ($realLength < 0 || $realLength > $numParts - $realOffset) {\n                throw new \\OutOfBoundsException(sprintf('Length %d is out of bounds', $length));\n            }\n        }\n\n        if ($realLength === 0) {\n            // Empty slice is represented as null\n            return null;\n        }\n\n        return new static(array_slice($parts, $realOffset, $realLength), $this->attributes);\n    }\n\n    /**\n     * Concatenate two names, yielding a new Name instance.\n     *\n     * The type of the generated instance depends on which class this method is called on, for\n     * example Name\\FullyQualified::concat() will yield a Name\\FullyQualified instance.\n     *\n     * If one of the arguments is null, a new instance of the other name will be returned. If both\n     * arguments are null, null will be returned. As such, writing\n     *     Name::concat($namespace, $shortName)\n     * where $namespace is a Name node or null will work as expected.\n     *\n     * @param string|string[]|self|null $name1 The first name\n     * @param string|string[]|self|null $name2 The second name\n     * @param array<string, mixed> $attributes Attributes to assign to concatenated name\n     *\n     * @return static|null Concatenated name\n     */\n    public static function concat($name1, $name2, array $attributes = []) {\n        if (null === $name1 && null === $name2) {\n            return null;\n        }\n        if (null === $name1) {\n            return new static($name2, $attributes);\n        }\n        if (null === $name2) {\n            return new static($name1, $attributes);\n        } else {\n            return new static(\n                self::prepareName($name1) . '\\\\' . self::prepareName($name2), $attributes\n            );\n        }\n    }\n\n    /**\n     * Prepares a (string, array or Name node) name for use in name changing methods by converting\n     * it to a string.\n     *\n     * @param string|string[]|self $name Name to prepare\n     *\n     * @psalm-return non-empty-string\n     * @return string Prepared name\n     */\n    private static function prepareName($name): string {\n        if (\\is_string($name)) {\n            if ('' === $name) {\n                throw new \\InvalidArgumentException('Name cannot be empty');\n            }\n\n            return $name;\n        }\n        if (\\is_array($name)) {\n            if (empty($name)) {\n                throw new \\InvalidArgumentException('Name cannot be empty');\n            }\n\n            return implode('\\\\', $name);\n        }\n        if ($name instanceof self) {\n            return $name->name;\n        }\n\n        throw new \\InvalidArgumentException(\n            'Expected string, array of parts or Name instance'\n        );\n    }\n\n    public function getType(): string {\n        return 'Name';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/NullableType.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\n\nclass NullableType extends ComplexType {\n    /** @var Identifier|Name Type */\n    public Node $type;\n\n    /**\n     * Constructs a nullable type (wrapping another type).\n     *\n     * @param Identifier|Name $type Type\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node $type, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->type = $type;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['type'];\n    }\n\n    public function getType(): string {\n        return 'NullableType';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Param.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass Param extends NodeAbstract {\n    /** @var null|Identifier|Name|ComplexType Type declaration */\n    public ?Node $type;\n    /** @var bool Whether parameter is passed by reference */\n    public bool $byRef;\n    /** @var bool Whether this is a variadic argument */\n    public bool $variadic;\n    /** @var Expr\\Variable|Expr\\Error Parameter variable */\n    public Expr $var;\n    /** @var null|Expr Default value */\n    public ?Expr $default;\n    /** @var int Optional visibility flags */\n    public int $flags;\n    /** @var AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n    /** @var PropertyHook[] Property hooks for promoted properties */\n    public array $hooks;\n\n    /**\n     * Constructs a parameter node.\n     *\n     * @param Expr\\Variable|Expr\\Error $var Parameter variable\n     * @param null|Expr $default Default value\n     * @param null|Identifier|Name|ComplexType $type Type declaration\n     * @param bool $byRef Whether is passed by reference\n     * @param bool $variadic Whether this is a variadic argument\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param int $flags Optional visibility flags\n     * @param list<AttributeGroup> $attrGroups PHP attribute groups\n     * @param PropertyHook[] $hooks Property hooks for promoted properties\n     */\n    public function __construct(\n        Expr $var, ?Expr $default = null, ?Node $type = null,\n        bool $byRef = false, bool $variadic = false,\n        array $attributes = [],\n        int $flags = 0,\n        array $attrGroups = [],\n        array $hooks = []\n    ) {\n        $this->attributes = $attributes;\n        $this->type = $type;\n        $this->byRef = $byRef;\n        $this->variadic = $variadic;\n        $this->var = $var;\n        $this->default = $default;\n        $this->flags = $flags;\n        $this->attrGroups = $attrGroups;\n        $this->hooks = $hooks;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'type', 'byRef', 'variadic', 'var', 'default', 'hooks'];\n    }\n\n    public function getType(): string {\n        return 'Param';\n    }\n\n    /**\n     * Whether this parameter uses constructor property promotion.\n     */\n    public function isPromoted(): bool {\n        return $this->flags !== 0 || $this->hooks !== [];\n    }\n\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    public function isPublic(): bool {\n        $public = (bool) ($this->flags & Modifiers::PUBLIC);\n        if ($public) {\n            return true;\n        }\n\n        if (!$this->isPromoted()) {\n            return false;\n        }\n\n        return ($this->flags & Modifiers::VISIBILITY_MASK) === 0;\n    }\n\n    public function isProtected(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED);\n    }\n\n    public function isPrivate(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE);\n    }\n\n    public function isReadonly(): bool {\n        return (bool) ($this->flags & Modifiers::READONLY);\n    }\n\n    /**\n     * Whether the promoted property has explicit public(set) visibility.\n     */\n    public function isPublicSet(): bool {\n        return (bool) ($this->flags & Modifiers::PUBLIC_SET);\n    }\n\n    /**\n     * Whether the promoted property has explicit protected(set) visibility.\n     */\n    public function isProtectedSet(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED_SET);\n    }\n\n    /**\n     * Whether the promoted property has explicit private(set) visibility.\n     */\n    public function isPrivateSet(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE_SET);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/PropertyHook.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node\\Expr\\Assign;\nuse PhpParser\\Node\\Expr\\PropertyFetch;\nuse PhpParser\\Node\\Expr\\Variable;\nuse PhpParser\\Node\\Stmt\\Expression;\nuse PhpParser\\Node\\Stmt\\Return_;\nuse PhpParser\\NodeAbstract;\n\nclass PropertyHook extends NodeAbstract implements FunctionLike {\n    /** @var AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n    /** @var int Modifiers */\n    public int $flags;\n    /** @var bool Whether hook returns by reference */\n    public bool $byRef;\n    /** @var Identifier Hook name */\n    public Identifier $name;\n    /** @var Param[] Parameters */\n    public array $params;\n    /** @var null|Expr|Stmt[] Hook body */\n    public $body;\n\n    /**\n     * Constructs a property hook node.\n     *\n     * @param string|Identifier $name Hook name\n     * @param null|Expr|Stmt[] $body Hook body\n     * @param array{\n     *     flags?: int,\n     *     byRef?: bool,\n     *     params?: Param[],\n     *     attrGroups?: AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'flags       => 0      : Flags\n     *             'byRef'      => false  : Whether hook returns by reference\n     *             'params'     => array(): Parameters\n     *             'attrGroups' => array(): PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, $body, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n        $this->body = $body;\n        $this->flags = $subNodes['flags'] ?? 0;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->params = $subNodes['params'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function returnsByRef(): bool {\n        return $this->byRef;\n    }\n\n    public function getParams(): array {\n        return $this->params;\n    }\n\n    public function getReturnType() {\n        return null;\n    }\n\n    /**\n     * Whether the property hook is final.\n     */\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    public function getStmts(): ?array {\n        if ($this->body instanceof Expr) {\n            $name = $this->name->toLowerString();\n            if ($name === 'get') {\n                return [new Return_($this->body)];\n            }\n            if ($name === 'set') {\n                if (!$this->hasAttribute('propertyName')) {\n                    throw new \\LogicException(\n                        'Can only use getStmts() on a \"set\" hook if the \"propertyName\" attribute is set');\n                }\n\n                $propName = $this->getAttribute('propertyName');\n                $prop = new PropertyFetch(new Variable('this'), (string) $propName);\n                return [new Expression(new Assign($prop, $this->body))];\n            }\n            throw new \\LogicException('Unknown property hook \"' . $name . '\"');\n        }\n        return $this->body;\n    }\n\n    public function getAttrGroups(): array {\n        return $this->attrGroups;\n    }\n\n    public function getType(): string {\n        return 'PropertyHook';\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'body'];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/PropertyItem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass PropertyItem extends NodeAbstract {\n    /** @var Node\\VarLikeIdentifier Name */\n    public VarLikeIdentifier $name;\n    /** @var null|Node\\Expr Default */\n    public ?Expr $default;\n\n    /**\n     * Constructs a class property item node.\n     *\n     * @param string|Node\\VarLikeIdentifier $name Name\n     * @param null|Node\\Expr $default Default value\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, ?Node\\Expr $default = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Node\\VarLikeIdentifier($name) : $name;\n        $this->default = $default;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'default'];\n    }\n\n    public function getType(): string {\n        return 'PropertyItem';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(PropertyItem::class, Stmt\\PropertyProperty::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/DNumber.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nrequire __DIR__ . '/Float_.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\Scalar\\Float_ instead.\n     */\n    class DNumber extends Float_ {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Encapsed.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nrequire __DIR__ . '/InterpolatedString.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\Scalar\\InterpolatedString instead.\n     */\n    class Encapsed extends InterpolatedString {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/EncapsedStringPart.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Node\\InterpolatedStringPart;\n\nrequire __DIR__ . '/../InterpolatedStringPart.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\InterpolatedStringPart instead.\n     */\n    class EncapsedStringPart extends InterpolatedStringPart {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Float_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Node\\Scalar;\n\nclass Float_ extends Scalar {\n    /** @var float Number value */\n    public float $value;\n\n    /**\n     * Constructs a float number scalar node.\n     *\n     * @param float $value Value of the number\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(float $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['value'];\n    }\n\n    /**\n     * @param mixed[] $attributes\n     */\n    public static function fromString(string $str, array $attributes = []): Float_ {\n        $attributes['rawValue'] = $str;\n        $float = self::parse($str);\n\n        return new Float_($float, $attributes);\n    }\n\n    /**\n     * @internal\n     *\n     * Parses a DNUMBER token like PHP would.\n     *\n     * @param string $str A string number\n     *\n     * @return float The parsed number\n     */\n    public static function parse(string $str): float {\n        $str = str_replace('_', '', $str);\n\n        // Check whether this is one of the special integer notations.\n        if ('0' === $str[0]) {\n            // hex\n            if ('x' === $str[1] || 'X' === $str[1]) {\n                // PHP 8.6 warns when hexdec() produces a float.\n                return @hexdec($str);\n            }\n\n            // bin\n            if ('b' === $str[1] || 'B' === $str[1]) {\n                // PHP 8.6 warns when bindec() produces a float.\n                return @bindec($str);\n            }\n\n            // oct, but only if the string does not contain any of '.eE'.\n            if (false === strpbrk($str, '.eE')) {\n                // substr($str, 0, strcspn($str, '89')) cuts the string at the first invalid digit\n                // (8 or 9) so that only the digits before that are used.\n                // PHP 8.6 warns when octdec() produces a float.\n                return @octdec(substr($str, 0, strcspn($str, '89')));\n            }\n        }\n\n        // dec\n        return (float) $str;\n    }\n\n    public function getType(): string {\n        return 'Scalar_Float';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(Float_::class, DNumber::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/Int_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Error;\nuse PhpParser\\Node\\Scalar;\n\nclass Int_ extends Scalar {\n    /* For use in \"kind\" attribute */\n    public const KIND_BIN = 2;\n    public const KIND_OCT = 8;\n    public const KIND_DEC = 10;\n    public const KIND_HEX = 16;\n\n    /** @var int Number value */\n    public int $value;\n\n    /**\n     * Constructs an integer number scalar node.\n     *\n     * @param int $value Value of the number\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(int $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['value'];\n    }\n\n    /**\n     * Constructs an Int node from a string number literal.\n     *\n     * @param string $str String number literal (decimal, octal, hex or binary)\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5)\n     *\n     * @return Int_ The constructed LNumber, including kind attribute\n     */\n    public static function fromString(string $str, array $attributes = [], bool $allowInvalidOctal = false): Int_ {\n        $attributes['rawValue'] = $str;\n\n        $str = str_replace('_', '', $str);\n\n        if ('0' !== $str[0] || '0' === $str) {\n            $attributes['kind'] = Int_::KIND_DEC;\n            return new Int_((int) $str, $attributes);\n        }\n\n        if ('x' === $str[1] || 'X' === $str[1]) {\n            $attributes['kind'] = Int_::KIND_HEX;\n            return new Int_(hexdec($str), $attributes);\n        }\n\n        if ('b' === $str[1] || 'B' === $str[1]) {\n            $attributes['kind'] = Int_::KIND_BIN;\n            return new Int_(bindec($str), $attributes);\n        }\n\n        if (!$allowInvalidOctal && strpbrk($str, '89')) {\n            throw new Error('Invalid numeric literal', $attributes);\n        }\n\n        // Strip optional explicit octal prefix.\n        if ('o' === $str[1] || 'O' === $str[1]) {\n            $str = substr($str, 2);\n        }\n\n        // use intval instead of octdec to get proper cutting behavior with malformed numbers\n        $attributes['kind'] = Int_::KIND_OCT;\n        return new Int_(intval($str, 8), $attributes);\n    }\n\n    public function getType(): string {\n        return 'Scalar_Int';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(Int_::class, LNumber::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/InterpolatedString.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\InterpolatedStringPart;\nuse PhpParser\\Node\\Scalar;\n\nclass InterpolatedString extends Scalar {\n    /** @var (Expr|InterpolatedStringPart)[] list of string parts */\n    public array $parts;\n\n    /**\n     * Constructs an interpolated string node.\n     *\n     * @param (Expr|InterpolatedStringPart)[] $parts Interpolated string parts\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $parts, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->parts = $parts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['parts'];\n    }\n\n    public function getType(): string {\n        return 'Scalar_InterpolatedString';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(InterpolatedString::class, Encapsed::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/LNumber.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nrequire __DIR__ . '/Int_.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\Scalar\\Int_ instead.\n     */\n    class LNumber extends Int_ {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Class_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Class_ extends MagicConst {\n    public function getName(): string {\n        return '__CLASS__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Class';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Dir.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Dir extends MagicConst {\n    public function getName(): string {\n        return '__DIR__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Dir';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/File.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass File extends MagicConst {\n    public function getName(): string {\n        return '__FILE__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_File';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Function_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Function_ extends MagicConst {\n    public function getName(): string {\n        return '__FUNCTION__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Function';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Line.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Line extends MagicConst {\n    public function getName(): string {\n        return '__LINE__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Line';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Method.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Method extends MagicConst {\n    public function getName(): string {\n        return '__METHOD__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Method';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Namespace_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Namespace_ extends MagicConst {\n    public function getName(): string {\n        return '__NAMESPACE__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Namespace';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Property.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Property extends MagicConst {\n    public function getName(): string {\n        return '__PROPERTY__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Property';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst/Trait_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar\\MagicConst;\n\nuse PhpParser\\Node\\Scalar\\MagicConst;\n\nclass Trait_ extends MagicConst {\n    public function getName(): string {\n        return '__TRAIT__';\n    }\n\n    public function getType(): string {\n        return 'Scalar_MagicConst_Trait';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/MagicConst.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Node\\Scalar;\n\nabstract class MagicConst extends Scalar {\n    /**\n     * Constructs a magic constant node.\n     *\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $attributes = []) {\n        $this->attributes = $attributes;\n    }\n\n    public function getSubNodeNames(): array {\n        return [];\n    }\n\n    /**\n     * Get name of magic constant.\n     *\n     * @return string Name of magic constant\n     */\n    abstract public function getName(): string;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar/String_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Scalar;\n\nuse PhpParser\\Error;\nuse PhpParser\\Node\\Scalar;\n\nclass String_ extends Scalar {\n    /* For use in \"kind\" attribute */\n    public const KIND_SINGLE_QUOTED = 1;\n    public const KIND_DOUBLE_QUOTED = 2;\n    public const KIND_HEREDOC = 3;\n    public const KIND_NOWDOC = 4;\n\n    /** @var string String value */\n    public string $value;\n\n    /** @var array<string, string> Escaped character to its decoded value */\n    protected static array $replacements = [\n        '\\\\' => '\\\\',\n        '$'  =>  '$',\n        'n'  => \"\\n\",\n        'r'  => \"\\r\",\n        't'  => \"\\t\",\n        'f'  => \"\\f\",\n        'v'  => \"\\v\",\n        'e'  => \"\\x1B\",\n    ];\n\n    /**\n     * Constructs a string scalar node.\n     *\n     * @param string $value Value of the string\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(string $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['value'];\n    }\n\n    /**\n     * @param array<string, mixed> $attributes\n     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \\u escapes\n     */\n    public static function fromString(string $str, array $attributes = [], bool $parseUnicodeEscape = true): self {\n        $attributes['kind'] = ($str[0] === \"'\" || ($str[1] === \"'\" && ($str[0] === 'b' || $str[0] === 'B')))\n            ? Scalar\\String_::KIND_SINGLE_QUOTED\n            : Scalar\\String_::KIND_DOUBLE_QUOTED;\n\n        $attributes['rawValue'] = $str;\n\n        $string = self::parse($str, $parseUnicodeEscape);\n\n        return new self($string, $attributes);\n    }\n\n    /**\n     * @internal\n     *\n     * Parses a string token.\n     *\n     * @param string $str String token content\n     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \\u escapes\n     *\n     * @return string The parsed string\n     */\n    public static function parse(string $str, bool $parseUnicodeEscape = true): string {\n        $bLength = 0;\n        if ('b' === $str[0] || 'B' === $str[0]) {\n            $bLength = 1;\n        }\n\n        if ('\\'' === $str[$bLength]) {\n            return str_replace(\n                ['\\\\\\\\', '\\\\\\''],\n                ['\\\\', '\\''],\n                substr($str, $bLength + 1, -1)\n            );\n        } else {\n            return self::parseEscapeSequences(\n                substr($str, $bLength + 1, -1), '\"', $parseUnicodeEscape\n            );\n        }\n    }\n\n    /**\n     * @internal\n     *\n     * Parses escape sequences in strings (all string types apart from single quoted).\n     *\n     * @param string $str String without quotes\n     * @param null|string $quote Quote type\n     * @param bool $parseUnicodeEscape Whether to parse PHP 7 \\u escapes\n     *\n     * @return string String with escape sequences parsed\n     */\n    public static function parseEscapeSequences(string $str, ?string $quote, bool $parseUnicodeEscape = true): string {\n        if (null !== $quote) {\n            $str = str_replace('\\\\' . $quote, $quote, $str);\n        }\n\n        $extra = '';\n        if ($parseUnicodeEscape) {\n            $extra = '|u\\{([0-9a-fA-F]+)\\}';\n        }\n\n        return preg_replace_callback(\n            '~\\\\\\\\([\\\\\\\\$nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}' . $extra . ')~',\n            function ($matches) {\n                $str = $matches[1];\n\n                if (isset(self::$replacements[$str])) {\n                    return self::$replacements[$str];\n                }\n                if ('x' === $str[0] || 'X' === $str[0]) {\n                    return chr(hexdec(substr($str, 1)));\n                }\n                if ('u' === $str[0]) {\n                    // PHP 8.6 warns when hexdec() produces a float.\n                    $dec = @hexdec($matches[2]);\n                    // If it overflowed to float, treat as INT_MAX, it will throw an error anyway.\n                    return self::codePointToUtf8(\\is_int($dec) ? $dec : \\PHP_INT_MAX);\n                } else {\n                    return chr(octdec($str) & 255);\n                }\n            },\n            $str\n        );\n    }\n\n    /**\n     * Converts a Unicode code point to its UTF-8 encoded representation.\n     *\n     * @param int $num Code point\n     *\n     * @return string UTF-8 representation of code point\n     */\n    private static function codePointToUtf8(int $num): string {\n        if ($num <= 0x7F) {\n            return chr($num);\n        }\n        if ($num <= 0x7FF) {\n            return chr(($num >> 6) + 0xC0) . chr(($num & 0x3F) + 0x80);\n        }\n        if ($num <= 0xFFFF) {\n            return chr(($num >> 12) + 0xE0) . chr((($num >> 6) & 0x3F) + 0x80) . chr(($num & 0x3F) + 0x80);\n        }\n        if ($num <= 0x10FFFF) {\n            return chr(($num >> 18) + 0xF0) . chr((($num >> 12) & 0x3F) + 0x80)\n                 . chr((($num >> 6) & 0x3F) + 0x80) . chr(($num & 0x3F) + 0x80);\n        }\n        throw new Error('Invalid UTF-8 codepoint escape sequence: Codepoint too large');\n    }\n\n    public function getType(): string {\n        return 'Scalar_String';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Scalar.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nabstract class Scalar extends Expr {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/StaticVar.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\n\nclass StaticVar extends NodeAbstract {\n    /** @var Expr\\Variable Variable */\n    public Expr\\Variable $var;\n    /** @var null|Node\\Expr Default value */\n    public ?Expr $default;\n\n    /**\n     * Constructs a static variable node.\n     *\n     * @param Expr\\Variable $var Name\n     * @param null|Node\\Expr $default Default value\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(\n        Expr\\Variable $var, ?Node\\Expr $default = null, array $attributes = []\n    ) {\n        $this->attributes = $attributes;\n        $this->var = $var;\n        $this->default = $default;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['var', 'default'];\n    }\n\n    public function getType(): string {\n        return 'StaticVar';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(StaticVar::class, Stmt\\StaticVar::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Block.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Stmt;\n\nclass Block extends Stmt {\n    /** @var Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * A block of statements.\n     *\n     * @param Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $stmts, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->stmts = $stmts;\n    }\n\n    public function getType(): string {\n        return 'Stmt_Block';\n    }\n\n    public function getSubNodeNames(): array {\n        return ['stmts'];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Break_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Break_ extends Node\\Stmt {\n    /** @var null|Node\\Expr Number of loops to break */\n    public ?Node\\Expr $num;\n\n    /**\n     * Constructs a break node.\n     *\n     * @param null|Node\\Expr $num Number of loops to break\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Expr $num = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->num = $num;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['num'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Break';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Case_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Case_ extends Node\\Stmt {\n    /** @var null|Node\\Expr Condition (null for default) */\n    public ?Node\\Expr $cond;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a case node.\n     *\n     * @param null|Node\\Expr $cond Condition (null for default)\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Expr $cond, array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Case';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Catch_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\n\nclass Catch_ extends Node\\Stmt {\n    /** @var Node\\Name[] Types of exceptions to catch */\n    public array $types;\n    /** @var Expr\\Variable|null Variable for exception */\n    public ?Expr\\Variable $var;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a catch node.\n     *\n     * @param Node\\Name[] $types Types of exceptions to catch\n     * @param Expr\\Variable|null $var Variable for exception\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(\n        array $types, ?Expr\\Variable $var = null, array $stmts = [], array $attributes = []\n    ) {\n        $this->attributes = $attributes;\n        $this->types = $types;\n        $this->var = $var;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['types', 'var', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Catch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassConst.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\n\nclass ClassConst extends Node\\Stmt {\n    /** @var int Modifiers */\n    public int $flags;\n    /** @var Node\\Const_[] Constant declarations */\n    public array $consts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n    /** @var Node\\Identifier|Node\\Name|Node\\ComplexType|null Type declaration */\n    public ?Node $type;\n\n    /**\n     * Constructs a class const list node.\n     *\n     * @param Node\\Const_[] $consts Constant declarations\n     * @param int $flags Modifiers\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param list<Node\\AttributeGroup> $attrGroups PHP attribute groups\n     * @param null|Node\\Identifier|Node\\Name|Node\\ComplexType $type Type declaration\n     */\n    public function __construct(\n        array $consts,\n        int $flags = 0,\n        array $attributes = [],\n        array $attrGroups = [],\n        ?Node $type = null\n    ) {\n        $this->attributes = $attributes;\n        $this->flags = $flags;\n        $this->consts = $consts;\n        $this->attrGroups = $attrGroups;\n        $this->type = $type;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'type', 'consts'];\n    }\n\n    /**\n     * Whether constant is explicitly or implicitly public.\n     */\n    public function isPublic(): bool {\n        return ($this->flags & Modifiers::PUBLIC) !== 0\n            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;\n    }\n\n    /**\n     * Whether constant is protected.\n     */\n    public function isProtected(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED);\n    }\n\n    /**\n     * Whether constant is private.\n     */\n    public function isPrivate(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE);\n    }\n\n    /**\n     * Whether constant is final.\n     */\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    public function getType(): string {\n        return 'Stmt_ClassConst';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassLike.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\PropertyItem;\n\nabstract class ClassLike extends Node\\Stmt {\n    /** @var Node\\Identifier|null Name */\n    public ?Node\\Identifier $name;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /** @var Node\\Name|null Namespaced name (if using NameResolver) */\n    public ?Node\\Name $namespacedName;\n\n    /**\n     * @return list<TraitUse>\n     */\n    public function getTraitUses(): array {\n        $traitUses = [];\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof TraitUse) {\n                $traitUses[] = $stmt;\n            }\n        }\n        return $traitUses;\n    }\n\n    /**\n     * @return list<ClassConst>\n     */\n    public function getConstants(): array {\n        $constants = [];\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof ClassConst) {\n                $constants[] = $stmt;\n            }\n        }\n        return $constants;\n    }\n\n    /**\n     * @return list<Property>\n     */\n    public function getProperties(): array {\n        $properties = [];\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof Property) {\n                $properties[] = $stmt;\n            }\n        }\n        return $properties;\n    }\n\n    /**\n     * Gets property with the given name defined directly in this class/interface/trait.\n     *\n     * @param string $name Name of the property\n     *\n     * @return Property|null Property node or null if the property does not exist\n     */\n    public function getProperty(string $name): ?Property {\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof Property) {\n                foreach ($stmt->props as $prop) {\n                    if ($prop instanceof PropertyItem && $name === $prop->name->toString()) {\n                        return $stmt;\n                    }\n                }\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Gets all methods defined directly in this class/interface/trait\n     *\n     * @return list<ClassMethod>\n     */\n    public function getMethods(): array {\n        $methods = [];\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof ClassMethod) {\n                $methods[] = $stmt;\n            }\n        }\n        return $methods;\n    }\n\n    /**\n     * Gets method with the given name defined directly in this class/interface/trait.\n     *\n     * @param string $name Name of the method (compared case-insensitively)\n     *\n     * @return ClassMethod|null Method node or null if the method does not exist\n     */\n    public function getMethod(string $name): ?ClassMethod {\n        $lowerName = strtolower($name);\n        foreach ($this->stmts as $stmt) {\n            if ($stmt instanceof ClassMethod && $lowerName === $stmt->name->toLowerString()) {\n                return $stmt;\n            }\n        }\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ClassMethod.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\FunctionLike;\n\nclass ClassMethod extends Node\\Stmt implements FunctionLike {\n    /** @var int Flags */\n    public int $flags;\n    /** @var bool Whether to return by reference */\n    public bool $byRef;\n    /** @var Node\\Identifier Name */\n    public Node\\Identifier $name;\n    /** @var Node\\Param[] Parameters */\n    public array $params;\n    /** @var null|Node\\Identifier|Node\\Name|Node\\ComplexType Return type */\n    public ?Node $returnType;\n    /** @var Node\\Stmt[]|null Statements */\n    public ?array $stmts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /** @var array<string, bool> */\n    private static array $magicNames = [\n        '__construct'   => true,\n        '__destruct'    => true,\n        '__call'        => true,\n        '__callstatic'  => true,\n        '__get'         => true,\n        '__set'         => true,\n        '__isset'       => true,\n        '__unset'       => true,\n        '__sleep'       => true,\n        '__wakeup'      => true,\n        '__tostring'    => true,\n        '__set_state'   => true,\n        '__clone'       => true,\n        '__invoke'      => true,\n        '__debuginfo'   => true,\n        '__serialize'   => true,\n        '__unserialize' => true,\n    ];\n\n    /**\n     * Constructs a class method node.\n     *\n     * @param string|Node\\Identifier $name Name\n     * @param array{\n     *     flags?: int,\n     *     byRef?: bool,\n     *     params?: Node\\Param[],\n     *     returnType?: null|Node\\Identifier|Node\\Name|Node\\ComplexType,\n     *     stmts?: Node\\Stmt[]|null,\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'flags       => 0              : Flags\n     *             'byRef'      => false          : Whether to return by reference\n     *             'params'     => array()        : Parameters\n     *             'returnType' => null           : Return type\n     *             'stmts'      => array()        : Statements\n     *             'attrGroups' => array()        : PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->params = $subNodes['params'] ?? [];\n        $this->returnType = $subNodes['returnType'] ?? null;\n        $this->stmts = array_key_exists('stmts', $subNodes) ? $subNodes['stmts'] : [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'byRef', 'name', 'params', 'returnType', 'stmts'];\n    }\n\n    public function returnsByRef(): bool {\n        return $this->byRef;\n    }\n\n    public function getParams(): array {\n        return $this->params;\n    }\n\n    public function getReturnType() {\n        return $this->returnType;\n    }\n\n    public function getStmts(): ?array {\n        return $this->stmts;\n    }\n\n    public function getAttrGroups(): array {\n        return $this->attrGroups;\n    }\n\n    /**\n     * Whether the method is explicitly or implicitly public.\n     */\n    public function isPublic(): bool {\n        return ($this->flags & Modifiers::PUBLIC) !== 0\n            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;\n    }\n\n    /**\n     * Whether the method is protected.\n     */\n    public function isProtected(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED);\n    }\n\n    /**\n     * Whether the method is private.\n     */\n    public function isPrivate(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE);\n    }\n\n    /**\n     * Whether the method is abstract.\n     */\n    public function isAbstract(): bool {\n        return (bool) ($this->flags & Modifiers::ABSTRACT);\n    }\n\n    /**\n     * Whether the method is final.\n     */\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    /**\n     * Whether the method is static.\n     */\n    public function isStatic(): bool {\n        return (bool) ($this->flags & Modifiers::STATIC);\n    }\n\n    /**\n     * Whether the method is magic.\n     */\n    public function isMagic(): bool {\n        return isset(self::$magicNames[$this->name->toLowerString()]);\n    }\n\n    public function getType(): string {\n        return 'Stmt_ClassMethod';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Class_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\n\nclass Class_ extends ClassLike {\n    /** @deprecated Use Modifiers::PUBLIC instead */\n    public const MODIFIER_PUBLIC    =  1;\n    /** @deprecated Use Modifiers::PROTECTED instead */\n    public const MODIFIER_PROTECTED =  2;\n    /** @deprecated Use Modifiers::PRIVATE instead */\n    public const MODIFIER_PRIVATE   =  4;\n    /** @deprecated Use Modifiers::STATIC instead */\n    public const MODIFIER_STATIC    =  8;\n    /** @deprecated Use Modifiers::ABSTRACT instead */\n    public const MODIFIER_ABSTRACT  = 16;\n    /** @deprecated Use Modifiers::FINAL instead */\n    public const MODIFIER_FINAL     = 32;\n    /** @deprecated Use Modifiers::READONLY instead */\n    public const MODIFIER_READONLY  = 64;\n\n    /** @deprecated Use Modifiers::VISIBILITY_MASK instead */\n    public const VISIBILITY_MODIFIER_MASK = 7; // 1 | 2 | 4\n\n    /** @var int Modifiers */\n    public int $flags;\n    /** @var null|Node\\Name Name of extended class */\n    public ?Node\\Name $extends;\n    /** @var Node\\Name[] Names of implemented interfaces */\n    public array $implements;\n\n    /**\n     * Constructs a class node.\n     *\n     * @param string|Node\\Identifier|null $name Name\n     * @param array{\n     *     flags?: int,\n     *     extends?: Node\\Name|null,\n     *     implements?: Node\\Name[],\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'flags'       => 0      : Flags\n     *             'extends'     => null   : Name of extended class\n     *             'implements'  => array(): Names of implemented interfaces\n     *             'stmts'       => array(): Statements\n     *             'attrGroups'  => array(): PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->flags = $subNodes['flags'] ?? $subNodes['type'] ?? 0;\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->extends = $subNodes['extends'] ?? null;\n        $this->implements = $subNodes['implements'] ?? [];\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'name', 'extends', 'implements', 'stmts'];\n    }\n\n    /**\n     * Whether the class is explicitly abstract.\n     */\n    public function isAbstract(): bool {\n        return (bool) ($this->flags & Modifiers::ABSTRACT);\n    }\n\n    /**\n     * Whether the class is final.\n     */\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    public function isReadonly(): bool {\n        return (bool) ($this->flags & Modifiers::READONLY);\n    }\n\n    /**\n     * Whether the class is anonymous.\n     */\n    public function isAnonymous(): bool {\n        return null === $this->name;\n    }\n\n    public function getType(): string {\n        return 'Stmt_Class';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Const_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Const_ extends Node\\Stmt {\n    /** @var Node\\Const_[] Constant declarations */\n    public array $consts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /**\n     * Constructs a const list node.\n     *\n     * @param Node\\Const_[] $consts Constant declarations\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param list<Node\\AttributeGroup> $attrGroups PHP attribute groups\n     */\n    public function __construct(\n        array $consts,\n        array $attributes = [],\n        array $attrGroups = []\n    ) {\n        $this->attributes = $attributes;\n        $this->attrGroups = $attrGroups;\n        $this->consts = $consts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'consts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Const';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Continue_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Continue_ extends Node\\Stmt {\n    /** @var null|Node\\Expr Number of loops to continue */\n    public ?Node\\Expr $num;\n\n    /**\n     * Constructs a continue node.\n     *\n     * @param null|Node\\Expr $num Number of loops to continue\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Expr $num = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->num = $num;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['num'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Continue';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/DeclareDeclare.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\DeclareItem;\n\nrequire __DIR__ . '/../DeclareItem.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\DeclareItem instead.\n     */\n    class DeclareDeclare extends DeclareItem {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Declare_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\DeclareItem;\n\nclass Declare_ extends Node\\Stmt {\n    /** @var DeclareItem[] List of declares */\n    public array $declares;\n    /** @var Node\\Stmt[]|null Statements */\n    public ?array $stmts;\n\n    /**\n     * Constructs a declare node.\n     *\n     * @param DeclareItem[] $declares List of declares\n     * @param Node\\Stmt[]|null $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $declares, ?array $stmts = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->declares = $declares;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['declares', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Declare';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Do_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Do_ extends Node\\Stmt {\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var Node\\Expr Condition */\n    public Node\\Expr $cond;\n\n    /**\n     * Constructs a do while node.\n     *\n     * @param Node\\Expr $cond Condition\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['stmts', 'cond'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Do';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Echo_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Echo_ extends Node\\Stmt {\n    /** @var Node\\Expr[] Expressions */\n    public array $exprs;\n\n    /**\n     * Constructs an echo node.\n     *\n     * @param Node\\Expr[] $exprs Expressions\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $exprs, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->exprs = $exprs;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['exprs'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Echo';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/ElseIf_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass ElseIf_ extends Node\\Stmt {\n    /** @var Node\\Expr Condition */\n    public Node\\Expr $cond;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs an elseif node.\n     *\n     * @param Node\\Expr $cond Condition\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_ElseIf';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Else_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Else_ extends Node\\Stmt {\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs an else node.\n     *\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Else';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/EnumCase.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\AttributeGroup;\n\nclass EnumCase extends Node\\Stmt {\n    /** @var Node\\Identifier Enum case name */\n    public Node\\Identifier $name;\n    /** @var Node\\Expr|null Enum case expression */\n    public ?Node\\Expr $expr;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /**\n     * @param string|Node\\Identifier $name Enum case name\n     * @param Node\\Expr|null $expr Enum case expression\n     * @param list<AttributeGroup> $attrGroups PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, ?Node\\Expr $expr = null, array $attrGroups = [], array $attributes = []) {\n        parent::__construct($attributes);\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->expr = $expr;\n        $this->attrGroups = $attrGroups;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'name', 'expr'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_EnumCase';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Enum_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Enum_ extends ClassLike {\n    /** @var null|Node\\Identifier Scalar Type */\n    public ?Node $scalarType;\n    /** @var Node\\Name[] Names of implemented interfaces */\n    public array $implements;\n\n    /**\n     * @param string|Node\\Identifier|null $name Name\n     * @param array{\n     *     scalarType?: Node\\Identifier|null,\n     *     implements?: Node\\Name[],\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'scalarType'  => null    : Scalar type\n     *             'implements'  => array() : Names of implemented interfaces\n     *             'stmts'       => array() : Statements\n     *             'attrGroups'  => array() : PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->scalarType = $subNodes['scalarType'] ?? null;\n        $this->implements = $subNodes['implements'] ?? [];\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n\n        parent::__construct($attributes);\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'name', 'scalarType', 'implements', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Enum';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Expression.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\n/**\n * Represents statements of type \"expr;\"\n */\nclass Expression extends Node\\Stmt {\n    /** @var Node\\Expr Expression */\n    public Node\\Expr $expr;\n\n    /**\n     * Constructs an expression statement.\n     *\n     * @param Node\\Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $expr, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Expression';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Finally_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Finally_ extends Node\\Stmt {\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a finally node.\n     *\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Finally';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/For_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass For_ extends Node\\Stmt {\n    /** @var Node\\Expr[] Init expressions */\n    public array $init;\n    /** @var Node\\Expr[] Loop conditions */\n    public array $cond;\n    /** @var Node\\Expr[] Loop expressions */\n    public array $loop;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a for loop node.\n     *\n     * @param array{\n     *     init?: Node\\Expr[],\n     *     cond?: Node\\Expr[],\n     *     loop?: Node\\Expr[],\n     *     stmts?: Node\\Stmt[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'init'  => array(): Init expressions\n     *             'cond'  => array(): Loop conditions\n     *             'loop'  => array(): Loop expressions\n     *             'stmts' => array(): Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->init = $subNodes['init'] ?? [];\n        $this->cond = $subNodes['cond'] ?? [];\n        $this->loop = $subNodes['loop'] ?? [];\n        $this->stmts = $subNodes['stmts'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['init', 'cond', 'loop', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_For';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Foreach_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Foreach_ extends Node\\Stmt {\n    /** @var Node\\Expr Expression to iterate */\n    public Node\\Expr $expr;\n    /** @var null|Node\\Expr Variable to assign key to */\n    public ?Node\\Expr $keyVar;\n    /** @var bool Whether to assign value by reference */\n    public bool $byRef;\n    /** @var Node\\Expr Variable to assign value to */\n    public Node\\Expr $valueVar;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a foreach node.\n     *\n     * @param Node\\Expr $expr Expression to iterate\n     * @param Node\\Expr $valueVar Variable to assign value to\n     * @param array{\n     *     keyVar?: Node\\Expr|null,\n     *     byRef?: bool,\n     *     stmts?: Node\\Stmt[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'keyVar' => null   : Variable to assign key to\n     *             'byRef'  => false  : Whether to assign value by reference\n     *             'stmts'  => array(): Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $expr, Node\\Expr $valueVar, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n        $this->keyVar = $subNodes['keyVar'] ?? null;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->valueVar = $valueVar;\n        $this->stmts = $subNodes['stmts'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr', 'keyVar', 'byRef', 'valueVar', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Foreach';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Function_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\FunctionLike;\n\nclass Function_ extends Node\\Stmt implements FunctionLike {\n    /** @var bool Whether function returns by reference */\n    public bool $byRef;\n    /** @var Node\\Identifier Name */\n    public Node\\Identifier $name;\n    /** @var Node\\Param[] Parameters */\n    public array $params;\n    /** @var null|Node\\Identifier|Node\\Name|Node\\ComplexType Return type */\n    public ?Node $returnType;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n\n    /** @var Node\\Name|null Namespaced name (if using NameResolver) */\n    public ?Node\\Name $namespacedName;\n\n    /**\n     * Constructs a function node.\n     *\n     * @param string|Node\\Identifier $name Name\n     * @param array{\n     *     byRef?: bool,\n     *     params?: Node\\Param[],\n     *     returnType?: null|Node\\Identifier|Node\\Name|Node\\ComplexType,\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'byRef'      => false  : Whether to return by reference\n     *             'params'     => array(): Parameters\n     *             'returnType' => null   : Return type\n     *             'stmts'      => array(): Statements\n     *             'attrGroups' => array(): PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->byRef = $subNodes['byRef'] ?? false;\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->params = $subNodes['params'] ?? [];\n        $this->returnType = $subNodes['returnType'] ?? null;\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'byRef', 'name', 'params', 'returnType', 'stmts'];\n    }\n\n    public function returnsByRef(): bool {\n        return $this->byRef;\n    }\n\n    public function getParams(): array {\n        return $this->params;\n    }\n\n    public function getReturnType() {\n        return $this->returnType;\n    }\n\n    public function getAttrGroups(): array {\n        return $this->attrGroups;\n    }\n\n    /** @return Node\\Stmt[] */\n    public function getStmts(): array {\n        return $this->stmts;\n    }\n\n    public function getType(): string {\n        return 'Stmt_Function';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Global_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Global_ extends Node\\Stmt {\n    /** @var Node\\Expr[] Variables */\n    public array $vars;\n\n    /**\n     * Constructs a global variables list node.\n     *\n     * @param Node\\Expr[] $vars Variables to unset\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $vars, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->vars = $vars;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['vars'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Global';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Goto_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Stmt;\n\nclass Goto_ extends Stmt {\n    /** @var Identifier Name of label to jump to */\n    public Identifier $name;\n\n    /**\n     * Constructs a goto node.\n     *\n     * @param string|Identifier $name Name of label to jump to\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Goto';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/GroupUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\Node\\UseItem;\n\nclass GroupUse extends Stmt {\n    /**\n     * @var Use_::TYPE_* Type of group use\n     */\n    public int $type;\n    /** @var Name Prefix for uses */\n    public Name $prefix;\n    /** @var UseItem[] Uses */\n    public array $uses;\n\n    /**\n     * Constructs a group use node.\n     *\n     * @param Name $prefix Prefix for uses\n     * @param UseItem[] $uses Uses\n     * @param Use_::TYPE_* $type Type of group use\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Name $prefix, array $uses, int $type = Use_::TYPE_NORMAL, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->type = $type;\n        $this->prefix = $prefix;\n        $this->uses = $uses;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['type', 'prefix', 'uses'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_GroupUse';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/HaltCompiler.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Stmt;\n\nclass HaltCompiler extends Stmt {\n    /** @var string Remaining text after halt compiler statement. */\n    public string $remaining;\n\n    /**\n     * Constructs a __halt_compiler node.\n     *\n     * @param string $remaining Remaining text after halt compiler statement.\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(string $remaining, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->remaining = $remaining;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['remaining'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_HaltCompiler';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/If_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass If_ extends Node\\Stmt {\n    /** @var Node\\Expr Condition expression */\n    public Node\\Expr $cond;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var ElseIf_[] Elseif clauses */\n    public array $elseifs;\n    /** @var null|Else_ Else clause */\n    public ?Else_ $else;\n\n    /**\n     * Constructs an if node.\n     *\n     * @param Node\\Expr $cond Condition\n     * @param array{\n     *     stmts?: Node\\Stmt[],\n     *     elseifs?: ElseIf_[],\n     *     else?: Else_|null,\n     * } $subNodes Array of the following optional subnodes:\n     *             'stmts'   => array(): Statements\n     *             'elseifs' => array(): Elseif clauses\n     *             'else'    => null   : Else clause\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->elseifs = $subNodes['elseifs'] ?? [];\n        $this->else = $subNodes['else'] ?? null;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'stmts', 'elseifs', 'else'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_If';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/InlineHTML.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Stmt;\n\nclass InlineHTML extends Stmt {\n    /** @var string String */\n    public string $value;\n\n    /**\n     * Constructs an inline HTML node.\n     *\n     * @param string $value String\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(string $value, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->value = $value;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['value'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_InlineHTML';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Interface_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Interface_ extends ClassLike {\n    /** @var Node\\Name[] Extended interfaces */\n    public array $extends;\n\n    /**\n     * Constructs a class node.\n     *\n     * @param string|Node\\Identifier $name Name\n     * @param array{\n     *     extends?: Node\\Name[],\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'extends'    => array(): Name of extended interfaces\n     *             'stmts'      => array(): Statements\n     *             'attrGroups' => array(): PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->extends = $subNodes['extends'] ?? [];\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'name', 'extends', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Interface';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Label.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Stmt;\n\nclass Label extends Stmt {\n    /** @var Identifier Name */\n    public Identifier $name;\n\n    /**\n     * Constructs a label node.\n     *\n     * @param string|Identifier $name Name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Identifier($name) : $name;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Label';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Namespace_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Namespace_ extends Node\\Stmt {\n    /* For use in the \"kind\" attribute */\n    public const KIND_SEMICOLON = 1;\n    public const KIND_BRACED = 2;\n\n    /** @var null|Node\\Name Name */\n    public ?Node\\Name $name;\n    /** @var Node\\Stmt[] Statements */\n    public $stmts;\n\n    /**\n     * Constructs a namespace node.\n     *\n     * @param null|Node\\Name $name Name\n     * @param null|Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Name $name = null, ?array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = $name;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['name', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Namespace';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Nop.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\n/** Nop/empty statement (;). */\nclass Nop extends Node\\Stmt {\n    public function getSubNodeNames(): array {\n        return [];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Nop';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Property.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\ComplexType;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\PropertyItem;\n\nclass Property extends Node\\Stmt {\n    /** @var int Modifiers */\n    public int $flags;\n    /** @var PropertyItem[] Properties */\n    public array $props;\n    /** @var null|Identifier|Name|ComplexType Type declaration */\n    public ?Node $type;\n    /** @var Node\\AttributeGroup[] PHP attribute groups */\n    public array $attrGroups;\n    /** @var Node\\PropertyHook[] Property hooks */\n    public array $hooks;\n\n    /**\n     * Constructs a class property list node.\n     *\n     * @param int $flags Modifiers\n     * @param PropertyItem[] $props Properties\n     * @param array<string, mixed> $attributes Additional attributes\n     * @param null|Identifier|Name|ComplexType $type Type declaration\n     * @param Node\\AttributeGroup[] $attrGroups PHP attribute groups\n     * @param Node\\PropertyHook[] $hooks Property hooks\n     */\n    public function __construct(int $flags, array $props, array $attributes = [], ?Node $type = null, array $attrGroups = [], array $hooks = []) {\n        $this->attributes = $attributes;\n        $this->flags = $flags;\n        $this->props = $props;\n        $this->type = $type;\n        $this->attrGroups = $attrGroups;\n        $this->hooks = $hooks;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'flags', 'type', 'props', 'hooks'];\n    }\n\n    /**\n     * Whether the property is explicitly or implicitly public.\n     */\n    public function isPublic(): bool {\n        return ($this->flags & Modifiers::PUBLIC) !== 0\n            || ($this->flags & Modifiers::VISIBILITY_MASK) === 0;\n    }\n\n    /**\n     * Whether the property is protected.\n     */\n    public function isProtected(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED);\n    }\n\n    /**\n     * Whether the property is private.\n     */\n    public function isPrivate(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE);\n    }\n\n    /**\n     * Whether the property is static.\n     */\n    public function isStatic(): bool {\n        return (bool) ($this->flags & Modifiers::STATIC);\n    }\n\n    /**\n     * Whether the property is readonly.\n     */\n    public function isReadonly(): bool {\n        return (bool) ($this->flags & Modifiers::READONLY);\n    }\n\n    /**\n     * Whether the property is abstract.\n     */\n    public function isAbstract(): bool {\n        return (bool) ($this->flags & Modifiers::ABSTRACT);\n    }\n\n    /**\n     * Whether the property is final.\n     */\n    public function isFinal(): bool {\n        return (bool) ($this->flags & Modifiers::FINAL);\n    }\n\n    /**\n     * Whether the property has explicit public(set) visibility.\n     */\n    public function isPublicSet(): bool {\n        return (bool) ($this->flags & Modifiers::PUBLIC_SET);\n    }\n\n    /**\n     * Whether the property has explicit protected(set) visibility.\n     */\n    public function isProtectedSet(): bool {\n        return (bool) ($this->flags & Modifiers::PROTECTED_SET);\n    }\n\n    /**\n     * Whether the property has explicit private(set) visibility.\n     */\n    public function isPrivateSet(): bool {\n        return (bool) ($this->flags & Modifiers::PRIVATE_SET);\n    }\n\n    public function getType(): string {\n        return 'Stmt_Property';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/PropertyProperty.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\PropertyItem;\n\nrequire __DIR__ . '/../PropertyItem.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\PropertyItem instead.\n     */\n    class PropertyProperty extends PropertyItem {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Return_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Return_ extends Node\\Stmt {\n    /** @var null|Node\\Expr Expression */\n    public ?Node\\Expr $expr;\n\n    /**\n     * Constructs a return node.\n     *\n     * @param null|Node\\Expr $expr Expression\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Expr $expr = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->expr = $expr;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['expr'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Return';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/StaticVar.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nrequire __DIR__ . '/../StaticVar.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\StaticVar instead.\n     */\n    class StaticVar extends \\PhpParser\\Node\\StaticVar {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Static_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\StaticVar;\nuse PhpParser\\Node\\Stmt;\n\nclass Static_ extends Stmt {\n    /** @var StaticVar[] Variable definitions */\n    public array $vars;\n\n    /**\n     * Constructs a static variables list node.\n     *\n     * @param StaticVar[] $vars Variable definitions\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $vars, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->vars = $vars;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['vars'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Static';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Switch_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Switch_ extends Node\\Stmt {\n    /** @var Node\\Expr Condition */\n    public Node\\Expr $cond;\n    /** @var Case_[] Case list */\n    public array $cases;\n\n    /**\n     * Constructs a case node.\n     *\n     * @param Node\\Expr $cond Condition\n     * @param Case_[] $cases Case list\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $cases, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->cases = $cases;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'cases'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Switch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass TraitUse extends Node\\Stmt {\n    /** @var Node\\Name[] Traits */\n    public array $traits;\n    /** @var TraitUseAdaptation[] Adaptations */\n    public array $adaptations;\n\n    /**\n     * Constructs a trait use node.\n     *\n     * @param Node\\Name[] $traits Traits\n     * @param TraitUseAdaptation[] $adaptations Adaptations\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $traits, array $adaptations = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->traits = $traits;\n        $this->adaptations = $adaptations;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['traits', 'adaptations'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_TraitUse';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Alias.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt\\TraitUseAdaptation;\n\nuse PhpParser\\Node;\n\nclass Alias extends Node\\Stmt\\TraitUseAdaptation {\n    /** @var null|int New modifier */\n    public ?int $newModifier;\n    /** @var null|Node\\Identifier New name */\n    public ?Node\\Identifier $newName;\n\n    /**\n     * Constructs a trait use precedence adaptation node.\n     *\n     * @param null|Node\\Name $trait Trait name\n     * @param string|Node\\Identifier $method Method name\n     * @param null|int $newModifier New modifier\n     * @param null|string|Node\\Identifier $newName New name\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(?Node\\Name $trait, $method, ?int $newModifier, $newName, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->trait = $trait;\n        $this->method = \\is_string($method) ? new Node\\Identifier($method) : $method;\n        $this->newModifier = $newModifier;\n        $this->newName = \\is_string($newName) ? new Node\\Identifier($newName) : $newName;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['trait', 'method', 'newModifier', 'newName'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_TraitUseAdaptation_Alias';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation/Precedence.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt\\TraitUseAdaptation;\n\nuse PhpParser\\Node;\n\nclass Precedence extends Node\\Stmt\\TraitUseAdaptation {\n    /** @var Node\\Name[] Overwritten traits */\n    public array $insteadof;\n\n    /**\n     * Constructs a trait use precedence adaptation node.\n     *\n     * @param Node\\Name $trait Trait name\n     * @param string|Node\\Identifier $method Method name\n     * @param Node\\Name[] $insteadof Overwritten traits\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Name $trait, $method, array $insteadof, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->trait = $trait;\n        $this->method = \\is_string($method) ? new Node\\Identifier($method) : $method;\n        $this->insteadof = $insteadof;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['trait', 'method', 'insteadof'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_TraitUseAdaptation_Precedence';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TraitUseAdaptation.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nabstract class TraitUseAdaptation extends Node\\Stmt {\n    /** @var Node\\Name|null Trait name */\n    public ?Node\\Name $trait;\n    /** @var Node\\Identifier Method name */\n    public Node\\Identifier $method;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Trait_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Trait_ extends ClassLike {\n    /**\n     * Constructs a trait node.\n     *\n     * @param string|Node\\Identifier $name Name\n     * @param array{\n     *     stmts?: Node\\Stmt[],\n     *     attrGroups?: Node\\AttributeGroup[],\n     * } $subNodes Array of the following optional subnodes:\n     *             'stmts'      => array(): Statements\n     *             'attrGroups' => array(): PHP attribute groups\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct($name, array $subNodes = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->name = \\is_string($name) ? new Node\\Identifier($name) : $name;\n        $this->stmts = $subNodes['stmts'] ?? [];\n        $this->attrGroups = $subNodes['attrGroups'] ?? [];\n    }\n\n    public function getSubNodeNames(): array {\n        return ['attrGroups', 'name', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Trait';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/TryCatch.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass TryCatch extends Node\\Stmt {\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n    /** @var Catch_[] Catches */\n    public array $catches;\n    /** @var null|Finally_ Optional finally node */\n    public ?Finally_ $finally;\n\n    /**\n     * Constructs a try catch node.\n     *\n     * @param Node\\Stmt[] $stmts Statements\n     * @param Catch_[] $catches Catches\n     * @param null|Finally_ $finally Optional finally node\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $stmts, array $catches, ?Finally_ $finally = null, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->stmts = $stmts;\n        $this->catches = $catches;\n        $this->finally = $finally;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['stmts', 'catches', 'finally'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_TryCatch';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Unset_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass Unset_ extends Node\\Stmt {\n    /** @var Node\\Expr[] Variables to unset */\n    public array $vars;\n\n    /**\n     * Constructs an unset node.\n     *\n     * @param Node\\Expr[] $vars Variables to unset\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $vars, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->vars = $vars;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['vars'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Unset';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/UseUse.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\UseItem;\n\nrequire __DIR__ . '/../UseItem.php';\n\nif (false) {\n    /**\n     * For classmap-authoritative support.\n     *\n     * @deprecated use \\PhpParser\\Node\\UseItem instead.\n     */\n    class UseUse extends UseItem {\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/Use_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\Node\\UseItem;\n\nclass Use_ extends Stmt {\n    /**\n     * Unknown type. Both Stmt\\Use_ / Stmt\\GroupUse and Stmt\\UseUse have a $type property, one of them will always be\n     * TYPE_UNKNOWN while the other has one of the three other possible types. For normal use statements the type on the\n     * Stmt\\UseUse is unknown. It's only the other way around for mixed group use declarations.\n     */\n    public const TYPE_UNKNOWN = 0;\n    /** Class or namespace import */\n    public const TYPE_NORMAL = 1;\n    /** Function import */\n    public const TYPE_FUNCTION = 2;\n    /** Constant import */\n    public const TYPE_CONSTANT = 3;\n\n    /** @var self::TYPE_* Type of alias */\n    public int $type;\n    /** @var UseItem[] Aliases */\n    public array $uses;\n\n    /**\n     * Constructs an alias (use) list node.\n     *\n     * @param UseItem[] $uses Aliases\n     * @param Stmt\\Use_::TYPE_* $type Type of alias\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $uses, int $type = self::TYPE_NORMAL, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->type = $type;\n        $this->uses = $uses;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['type', 'uses'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_Use';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt/While_.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node\\Stmt;\n\nuse PhpParser\\Node;\n\nclass While_ extends Node\\Stmt {\n    /** @var Node\\Expr Condition */\n    public Node\\Expr $cond;\n    /** @var Node\\Stmt[] Statements */\n    public array $stmts;\n\n    /**\n     * Constructs a while node.\n     *\n     * @param Node\\Expr $cond Condition\n     * @param Node\\Stmt[] $stmts Statements\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Expr $cond, array $stmts = [], array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->cond = $cond;\n        $this->stmts = $stmts;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['cond', 'stmts'];\n    }\n\n    public function getType(): string {\n        return 'Stmt_While';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/Stmt.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\nabstract class Stmt extends NodeAbstract {\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/UnionType.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nclass UnionType extends ComplexType {\n    /** @var (Identifier|Name|IntersectionType)[] Types */\n    public array $types;\n\n    /**\n     * Constructs a union type.\n     *\n     * @param (Identifier|Name|IntersectionType)[] $types Types\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $types, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->types = $types;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['types'];\n    }\n\n    public function getType(): string {\n        return 'UnionType';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/UseItem.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeAbstract;\nuse PhpParser\\Node\\Stmt\\Use_;\n\nclass UseItem extends NodeAbstract {\n    /**\n     * @var Use_::TYPE_* One of the Stmt\\Use_::TYPE_* constants. Will only differ from TYPE_UNKNOWN for mixed group uses\n     */\n    public int $type;\n    /** @var Node\\Name Namespace, class, function or constant to alias */\n    public Name $name;\n    /** @var Identifier|null Alias */\n    public ?Identifier $alias;\n\n    /**\n     * Constructs an alias (use) item node.\n     *\n     * @param Node\\Name $name Namespace/Class to alias\n     * @param null|string|Identifier $alias Alias\n     * @param Use_::TYPE_* $type Type of the use element (for mixed group use only)\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(Node\\Name $name, $alias = null, int $type = Use_::TYPE_UNKNOWN, array $attributes = []) {\n        $this->attributes = $attributes;\n        $this->type = $type;\n        $this->name = $name;\n        $this->alias = \\is_string($alias) ? new Identifier($alias) : $alias;\n    }\n\n    public function getSubNodeNames(): array {\n        return ['type', 'name', 'alias'];\n    }\n\n    /**\n     * Get alias. If not explicitly given this is the last component of the used name.\n     */\n    public function getAlias(): Identifier {\n        if (null !== $this->alias) {\n            return $this->alias;\n        }\n\n        return new Identifier($this->name->getLast());\n    }\n\n    public function getType(): string {\n        return 'UseItem';\n    }\n}\n\n// @deprecated compatibility alias\nclass_alias(UseItem::class, Stmt\\UseUse::class);\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/VarLikeIdentifier.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\n/**\n * Represents a name that is written in source code with a leading dollar,\n * but is not a proper variable. The leading dollar is not stored as part of the name.\n *\n * Examples: Names in property declarations are formatted as variables. Names in static property\n * lookups are also formatted as variables.\n */\nclass VarLikeIdentifier extends Identifier {\n    public function getType(): string {\n        return 'VarLikeIdentifier';\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node/VariadicPlaceholder.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Node;\n\nuse PhpParser\\NodeAbstract;\n\n/**\n * Represents the \"...\" in \"foo(...)\" of the first-class callable syntax.\n */\nclass VariadicPlaceholder extends NodeAbstract {\n    /**\n     * Create a variadic argument placeholder (first-class callable syntax).\n     *\n     * @param array<string, mixed> $attributes Additional attributes\n     */\n    public function __construct(array $attributes = []) {\n        $this->attributes = $attributes;\n    }\n\n    public function getType(): string {\n        return 'VariadicPlaceholder';\n    }\n\n    public function getSubNodeNames(): array {\n        return [];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Node.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface Node {\n    /**\n     * Gets the type of the node.\n     *\n     * @psalm-return non-empty-string\n     * @return string Type of the node\n     */\n    public function getType(): string;\n\n    /**\n     * Gets the names of the sub nodes.\n     *\n     * @return string[] Names of sub nodes\n     */\n    public function getSubNodeNames(): array;\n\n    /**\n     * Gets line the node started in (alias of getStartLine).\n     *\n     * @return int Start line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     *\n     * @deprecated Use getStartLine() instead\n     */\n    public function getLine(): int;\n\n    /**\n     * Gets line the node started in.\n     *\n     * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default).\n     *\n     * @return int Start line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getStartLine(): int;\n\n    /**\n     * Gets the line the node ended in.\n     *\n     * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default).\n     *\n     * @return int End line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getEndLine(): int;\n\n    /**\n     * Gets the token offset of the first token that is part of this node.\n     *\n     * The offset is an index into the array returned by Lexer::getTokens().\n     *\n     * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int Token start position (or -1 if not available)\n     */\n    public function getStartTokenPos(): int;\n\n    /**\n     * Gets the token offset of the last token that is part of this node.\n     *\n     * The offset is an index into the array returned by Lexer::getTokens().\n     *\n     * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int Token end position (or -1 if not available)\n     */\n    public function getEndTokenPos(): int;\n\n    /**\n     * Gets the file offset of the first character that is part of this node.\n     *\n     * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int File start position (or -1 if not available)\n     */\n    public function getStartFilePos(): int;\n\n    /**\n     * Gets the file offset of the last character that is part of this node.\n     *\n     * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int File end position (or -1 if not available)\n     */\n    public function getEndFilePos(): int;\n\n    /**\n     * Gets all comments directly preceding this node.\n     *\n     * The comments are also available through the \"comments\" attribute.\n     *\n     * @return Comment[]\n     */\n    public function getComments(): array;\n\n    /**\n     * Gets the doc comment of the node.\n     *\n     * @return null|Comment\\Doc Doc comment object or null\n     */\n    public function getDocComment(): ?Comment\\Doc;\n\n    /**\n     * Sets the doc comment of the node.\n     *\n     * This will either replace an existing doc comment or add it to the comments array.\n     *\n     * @param Comment\\Doc $docComment Doc comment to set\n     */\n    public function setDocComment(Comment\\Doc $docComment): void;\n\n    /**\n     * Sets an attribute on a node.\n     *\n     * @param mixed $value\n     */\n    public function setAttribute(string $key, $value): void;\n\n    /**\n     * Returns whether an attribute exists.\n     */\n    public function hasAttribute(string $key): bool;\n\n    /**\n     * Returns the value of an attribute.\n     *\n     * @param mixed $default\n     *\n     * @return mixed\n     */\n    public function getAttribute(string $key, $default = null);\n\n    /**\n     * Returns all the attributes of this node.\n     *\n     * @return array<string, mixed>\n     */\n    public function getAttributes(): array;\n\n    /**\n     * Replaces all the attributes of this node.\n     *\n     * @param array<string, mixed> $attributes\n     */\n    public function setAttributes(array $attributes): void;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeAbstract.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nabstract class NodeAbstract implements Node, \\JsonSerializable {\n    /** @var array<string, mixed> Attributes */\n    protected array $attributes;\n\n    /**\n     * Creates a Node.\n     *\n     * @param array<string, mixed> $attributes Array of attributes\n     */\n    public function __construct(array $attributes = []) {\n        $this->attributes = $attributes;\n    }\n\n    /**\n     * Gets line the node started in (alias of getStartLine).\n     *\n     * @return int Start line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getLine(): int {\n        return $this->attributes['startLine'] ?? -1;\n    }\n\n    /**\n     * Gets line the node started in.\n     *\n     * Requires the 'startLine' attribute to be enabled in the lexer (enabled by default).\n     *\n     * @return int Start line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getStartLine(): int {\n        return $this->attributes['startLine'] ?? -1;\n    }\n\n    /**\n     * Gets the line the node ended in.\n     *\n     * Requires the 'endLine' attribute to be enabled in the lexer (enabled by default).\n     *\n     * @return int End line (or -1 if not available)\n     * @phpstan-return -1|positive-int\n     */\n    public function getEndLine(): int {\n        return $this->attributes['endLine'] ?? -1;\n    }\n\n    /**\n     * Gets the token offset of the first token that is part of this node.\n     *\n     * The offset is an index into the array returned by Lexer::getTokens().\n     *\n     * Requires the 'startTokenPos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int Token start position (or -1 if not available)\n     */\n    public function getStartTokenPos(): int {\n        return $this->attributes['startTokenPos'] ?? -1;\n    }\n\n    /**\n     * Gets the token offset of the last token that is part of this node.\n     *\n     * The offset is an index into the array returned by Lexer::getTokens().\n     *\n     * Requires the 'endTokenPos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int Token end position (or -1 if not available)\n     */\n    public function getEndTokenPos(): int {\n        return $this->attributes['endTokenPos'] ?? -1;\n    }\n\n    /**\n     * Gets the file offset of the first character that is part of this node.\n     *\n     * Requires the 'startFilePos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int File start position (or -1 if not available)\n     */\n    public function getStartFilePos(): int {\n        return $this->attributes['startFilePos'] ?? -1;\n    }\n\n    /**\n     * Gets the file offset of the last character that is part of this node.\n     *\n     * Requires the 'endFilePos' attribute to be enabled in the lexer (DISABLED by default).\n     *\n     * @return int File end position (or -1 if not available)\n     */\n    public function getEndFilePos(): int {\n        return $this->attributes['endFilePos'] ?? -1;\n    }\n\n    /**\n     * Gets all comments directly preceding this node.\n     *\n     * The comments are also available through the \"comments\" attribute.\n     *\n     * @return Comment[]\n     */\n    public function getComments(): array {\n        return $this->attributes['comments'] ?? [];\n    }\n\n    /**\n     * Gets the doc comment of the node.\n     *\n     * @return null|Comment\\Doc Doc comment object or null\n     */\n    public function getDocComment(): ?Comment\\Doc {\n        $comments = $this->getComments();\n        for ($i = count($comments) - 1; $i >= 0; $i--) {\n            $comment = $comments[$i];\n            if ($comment instanceof Comment\\Doc) {\n                return $comment;\n            }\n        }\n\n        return null;\n    }\n\n    /**\n     * Sets the doc comment of the node.\n     *\n     * This will either replace an existing doc comment or add it to the comments array.\n     *\n     * @param Comment\\Doc $docComment Doc comment to set\n     */\n    public function setDocComment(Comment\\Doc $docComment): void {\n        $comments = $this->getComments();\n        for ($i = count($comments) - 1; $i >= 0; $i--) {\n            if ($comments[$i] instanceof Comment\\Doc) {\n                // Replace existing doc comment.\n                $comments[$i] = $docComment;\n                $this->setAttribute('comments', $comments);\n                return;\n            }\n        }\n\n        // Append new doc comment.\n        $comments[] = $docComment;\n        $this->setAttribute('comments', $comments);\n    }\n\n    public function setAttribute(string $key, $value): void {\n        $this->attributes[$key] = $value;\n    }\n\n    public function hasAttribute(string $key): bool {\n        return array_key_exists($key, $this->attributes);\n    }\n\n    public function getAttribute(string $key, $default = null) {\n        if (array_key_exists($key, $this->attributes)) {\n            return $this->attributes[$key];\n        }\n\n        return $default;\n    }\n\n    public function getAttributes(): array {\n        return $this->attributes;\n    }\n\n    public function setAttributes(array $attributes): void {\n        $this->attributes = $attributes;\n    }\n\n    /**\n     * @return array<string, mixed>\n     */\n    public function jsonSerialize(): array {\n        return ['nodeType' => $this->getType()] + get_object_vars($this);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeDumper.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\Expr\\Array_;\nuse PhpParser\\Node\\Expr\\Include_;\nuse PhpParser\\Node\\Expr\\List_;\nuse PhpParser\\Node\\Scalar\\Int_;\nuse PhpParser\\Node\\Scalar\\InterpolatedString;\nuse PhpParser\\Node\\Scalar\\String_;\nuse PhpParser\\Node\\Stmt\\GroupUse;\nuse PhpParser\\Node\\Stmt\\Use_;\nuse PhpParser\\Node\\UseItem;\n\nclass NodeDumper {\n    private bool $dumpComments;\n    private bool $dumpPositions;\n    private bool $dumpOtherAttributes;\n    private ?string $code;\n    private string $res;\n    private string $nl;\n\n    private const IGNORE_ATTRIBUTES = [\n        'comments' => true,\n        'startLine' => true,\n        'endLine' => true,\n        'startFilePos' => true,\n        'endFilePos' => true,\n        'startTokenPos' => true,\n        'endTokenPos' => true,\n    ];\n\n    /**\n     * Constructs a NodeDumper.\n     *\n     * Supported options:\n     *  * bool dumpComments: Whether comments should be dumped.\n     *  * bool dumpPositions: Whether line/offset information should be dumped. To dump offset\n     *                        information, the code needs to be passed to dump().\n     *  * bool dumpOtherAttributes: Whether non-comment, non-position attributes should be dumped.\n     *\n     * @param array $options Options (see description)\n     */\n    public function __construct(array $options = []) {\n        $this->dumpComments = !empty($options['dumpComments']);\n        $this->dumpPositions = !empty($options['dumpPositions']);\n        $this->dumpOtherAttributes = !empty($options['dumpOtherAttributes']);\n    }\n\n    /**\n     * Dumps a node or array.\n     *\n     * @param array|Node $node Node or array to dump\n     * @param string|null $code Code corresponding to dumped AST. This only needs to be passed if\n     *                          the dumpPositions option is enabled and the dumping of node offsets\n     *                          is desired.\n     *\n     * @return string Dumped value\n     */\n    public function dump($node, ?string $code = null): string {\n        $this->code = $code;\n        $this->res = '';\n        $this->nl = \"\\n\";\n        $this->dumpRecursive($node, false);\n        return $this->res;\n    }\n\n    /** @param mixed $node */\n    protected function dumpRecursive($node, bool $indent = true): void {\n        if ($indent) {\n            $this->nl .= \"    \";\n        }\n        if ($node instanceof Node) {\n            $this->res .= $node->getType();\n            if ($this->dumpPositions && null !== $p = $this->dumpPosition($node)) {\n                $this->res .= $p;\n            }\n            $this->res .= '(';\n\n            foreach ($node->getSubNodeNames() as $key) {\n                $this->res .= \"$this->nl    \" . $key . ': ';\n\n                $value = $node->$key;\n                if (\\is_int($value)) {\n                    if ('flags' === $key || 'newModifier' === $key) {\n                        $this->res .= $this->dumpFlags($value);\n                        continue;\n                    }\n                    if ('type' === $key && $node instanceof Include_) {\n                        $this->res .= $this->dumpIncludeType($value);\n                        continue;\n                    }\n                    if ('type' === $key\n                            && ($node instanceof Use_ || $node instanceof UseItem || $node instanceof GroupUse)) {\n                        $this->res .= $this->dumpUseType($value);\n                        continue;\n                    }\n                }\n                $this->dumpRecursive($value);\n            }\n\n            if ($this->dumpComments && $comments = $node->getComments()) {\n                $this->res .= \"$this->nl    comments: \";\n                $this->dumpRecursive($comments);\n            }\n\n            if ($this->dumpOtherAttributes) {\n                foreach ($node->getAttributes() as $key => $value) {\n                    if (isset(self::IGNORE_ATTRIBUTES[$key])) {\n                        continue;\n                    }\n\n                    $this->res .= \"$this->nl    $key: \";\n                    if (\\is_int($value)) {\n                        if ('kind' === $key) {\n                            if ($node instanceof Int_) {\n                                $this->res .= $this->dumpIntKind($value);\n                                continue;\n                            }\n                            if ($node instanceof String_ || $node instanceof InterpolatedString) {\n                                $this->res .= $this->dumpStringKind($value);\n                                continue;\n                            }\n                            if ($node instanceof Array_) {\n                                $this->res .= $this->dumpArrayKind($value);\n                                continue;\n                            }\n                            if ($node instanceof List_) {\n                                $this->res .= $this->dumpListKind($value);\n                                continue;\n                            }\n                        }\n                    }\n                    $this->dumpRecursive($value);\n                }\n            }\n            $this->res .= \"$this->nl)\";\n        } elseif (\\is_array($node)) {\n            $this->res .= 'array(';\n            foreach ($node as $key => $value) {\n                $this->res .= \"$this->nl    \" . $key . ': ';\n                $this->dumpRecursive($value);\n            }\n            $this->res .= \"$this->nl)\";\n        } elseif ($node instanceof Comment) {\n            $this->res .= \\str_replace(\"\\n\", $this->nl, $node->getReformattedText());\n        } elseif (\\is_string($node)) {\n            $this->res .= \\str_replace(\"\\n\", $this->nl, $node);\n        } elseif (\\is_int($node) || \\is_float($node)) {\n            $this->res .= $node;\n        } elseif (null === $node) {\n            $this->res .= 'null';\n        } elseif (false === $node) {\n            $this->res .= 'false';\n        } elseif (true === $node) {\n            $this->res .= 'true';\n        } else {\n            throw new \\InvalidArgumentException('Can only dump nodes and arrays.');\n        }\n        if ($indent) {\n            $this->nl = \\substr($this->nl, 0, -4);\n        }\n    }\n\n    protected function dumpFlags(int $flags): string {\n        $strs = [];\n        if ($flags & Modifiers::PUBLIC) {\n            $strs[] = 'PUBLIC';\n        }\n        if ($flags & Modifiers::PROTECTED) {\n            $strs[] = 'PROTECTED';\n        }\n        if ($flags & Modifiers::PRIVATE) {\n            $strs[] = 'PRIVATE';\n        }\n        if ($flags & Modifiers::ABSTRACT) {\n            $strs[] = 'ABSTRACT';\n        }\n        if ($flags & Modifiers::STATIC) {\n            $strs[] = 'STATIC';\n        }\n        if ($flags & Modifiers::FINAL) {\n            $strs[] = 'FINAL';\n        }\n        if ($flags & Modifiers::READONLY) {\n            $strs[] = 'READONLY';\n        }\n        if ($flags & Modifiers::PUBLIC_SET) {\n            $strs[] = 'PUBLIC_SET';\n        }\n        if ($flags & Modifiers::PROTECTED_SET) {\n            $strs[] = 'PROTECTED_SET';\n        }\n        if ($flags & Modifiers::PRIVATE_SET) {\n            $strs[] = 'PRIVATE_SET';\n        }\n\n        if ($strs) {\n            return implode(' | ', $strs) . ' (' . $flags . ')';\n        } else {\n            return (string) $flags;\n        }\n    }\n\n    /** @param array<int, string> $map */\n    private function dumpEnum(int $value, array $map): string {\n        if (!isset($map[$value])) {\n            return (string) $value;\n        }\n        return $map[$value] . ' (' . $value . ')';\n    }\n\n    private function dumpIncludeType(int $type): string {\n        return $this->dumpEnum($type, [\n            Include_::TYPE_INCLUDE      => 'TYPE_INCLUDE',\n            Include_::TYPE_INCLUDE_ONCE => 'TYPE_INCLUDE_ONCE',\n            Include_::TYPE_REQUIRE      => 'TYPE_REQUIRE',\n            Include_::TYPE_REQUIRE_ONCE => 'TYPE_REQUIRE_ONCE',\n        ]);\n    }\n\n    private function dumpUseType(int $type): string {\n        return $this->dumpEnum($type, [\n            Use_::TYPE_UNKNOWN  => 'TYPE_UNKNOWN',\n            Use_::TYPE_NORMAL   => 'TYPE_NORMAL',\n            Use_::TYPE_FUNCTION => 'TYPE_FUNCTION',\n            Use_::TYPE_CONSTANT => 'TYPE_CONSTANT',\n        ]);\n    }\n\n    private function dumpIntKind(int $kind): string {\n        return $this->dumpEnum($kind, [\n            Int_::KIND_BIN => 'KIND_BIN',\n            Int_::KIND_OCT => 'KIND_OCT',\n            Int_::KIND_DEC => 'KIND_DEC',\n            Int_::KIND_HEX => 'KIND_HEX',\n        ]);\n    }\n\n    private function dumpStringKind(int $kind): string {\n        return $this->dumpEnum($kind, [\n            String_::KIND_SINGLE_QUOTED => 'KIND_SINGLE_QUOTED',\n            String_::KIND_DOUBLE_QUOTED => 'KIND_DOUBLE_QUOTED',\n            String_::KIND_HEREDOC => 'KIND_HEREDOC',\n            String_::KIND_NOWDOC => 'KIND_NOWDOC',\n        ]);\n    }\n\n    private function dumpArrayKind(int $kind): string {\n        return $this->dumpEnum($kind, [\n            Array_::KIND_LONG => 'KIND_LONG',\n            Array_::KIND_SHORT => 'KIND_SHORT',\n        ]);\n    }\n\n    private function dumpListKind(int $kind): string {\n        return $this->dumpEnum($kind, [\n            List_::KIND_LIST => 'KIND_LIST',\n            List_::KIND_ARRAY => 'KIND_ARRAY',\n        ]);\n    }\n\n    /**\n     * Dump node position, if possible.\n     *\n     * @param Node $node Node for which to dump position\n     *\n     * @return string|null Dump of position, or null if position information not available\n     */\n    protected function dumpPosition(Node $node): ?string {\n        if (!$node->hasAttribute('startLine') || !$node->hasAttribute('endLine')) {\n            return null;\n        }\n\n        $start = $node->getStartLine();\n        $end = $node->getEndLine();\n        if ($node->hasAttribute('startFilePos') && $node->hasAttribute('endFilePos')\n            && null !== $this->code\n        ) {\n            $start .= ':' . $this->toColumn($this->code, $node->getStartFilePos());\n            $end .= ':' . $this->toColumn($this->code, $node->getEndFilePos());\n        }\n        return \"[$start - $end]\";\n    }\n\n    // Copied from Error class\n    private function toColumn(string $code, int $pos): int {\n        if ($pos > strlen($code)) {\n            throw new \\RuntimeException('Invalid position information');\n        }\n\n        $lineStartPos = strrpos($code, \"\\n\", $pos - strlen($code));\n        if (false === $lineStartPos) {\n            $lineStartPos = -1;\n        }\n\n        return $pos - $lineStartPos;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeFinder.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\NodeVisitor\\FindingVisitor;\nuse PhpParser\\NodeVisitor\\FirstFindingVisitor;\n\nclass NodeFinder {\n    /**\n     * Find all nodes satisfying a filter callback.\n     *\n     * @param Node|Node[] $nodes Single node or array of nodes to search in\n     * @param callable $filter Filter callback: function(Node $node) : bool\n     *\n     * @return Node[] Found nodes satisfying the filter callback\n     */\n    public function find($nodes, callable $filter): array {\n        if ($nodes === []) {\n            return [];\n        }\n\n        if (!is_array($nodes)) {\n            $nodes = [$nodes];\n        }\n\n        $visitor = new FindingVisitor($filter);\n\n        $traverser = new NodeTraverser($visitor);\n        $traverser->traverse($nodes);\n\n        return $visitor->getFoundNodes();\n    }\n\n    /**\n     * Find all nodes that are instances of a certain class.\n\n     * @template TNode as Node\n     *\n     * @param Node|Node[] $nodes Single node or array of nodes to search in\n     * @param class-string<TNode> $class Class name\n     *\n     * @return TNode[] Found nodes (all instances of $class)\n     */\n    public function findInstanceOf($nodes, string $class): array {\n        return $this->find($nodes, function ($node) use ($class) {\n            return $node instanceof $class;\n        });\n    }\n\n    /**\n     * Find first node satisfying a filter callback.\n     *\n     * @param Node|Node[] $nodes Single node or array of nodes to search in\n     * @param callable $filter Filter callback: function(Node $node) : bool\n     *\n     * @return null|Node Found node (or null if none found)\n     */\n    public function findFirst($nodes, callable $filter): ?Node {\n        if ($nodes === []) {\n            return null;\n        }\n\n        if (!is_array($nodes)) {\n            $nodes = [$nodes];\n        }\n\n        $visitor = new FirstFindingVisitor($filter);\n\n        $traverser = new NodeTraverser($visitor);\n        $traverser->traverse($nodes);\n\n        return $visitor->getFoundNode();\n    }\n\n    /**\n     * Find first node that is an instance of a certain class.\n     *\n     * @template TNode as Node\n     *\n     * @param Node|Node[] $nodes Single node or array of nodes to search in\n     * @param class-string<TNode> $class Class name\n     *\n     * @return null|TNode Found node, which is an instance of $class (or null if none found)\n     */\n    public function findFirstInstanceOf($nodes, string $class): ?Node {\n        return $this->findFirst($nodes, function ($node) use ($class) {\n            return $node instanceof $class;\n        });\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nclass NodeTraverser implements NodeTraverserInterface {\n    /**\n     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CHILDREN instead.\n     */\n    public const DONT_TRAVERSE_CHILDREN = NodeVisitor::DONT_TRAVERSE_CHILDREN;\n\n    /**\n     * @deprecated Use NodeVisitor::STOP_TRAVERSAL instead.\n     */\n    public const STOP_TRAVERSAL = NodeVisitor::STOP_TRAVERSAL;\n\n    /**\n     * @deprecated Use NodeVisitor::REMOVE_NODE instead.\n     */\n    public const REMOVE_NODE = NodeVisitor::REMOVE_NODE;\n\n    /**\n     * @deprecated Use NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN instead.\n     */\n    public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN;\n\n    /** @var list<NodeVisitor> Visitors */\n    protected array $visitors = [];\n\n    /** @var bool Whether traversal should be stopped */\n    protected bool $stopTraversal;\n\n    /**\n     * Create a traverser with the given visitors.\n     *\n     * @param NodeVisitor ...$visitors Node visitors\n     */\n    public function __construct(NodeVisitor ...$visitors) {\n        $this->visitors = $visitors;\n    }\n\n    /**\n     * Adds a visitor.\n     *\n     * @param NodeVisitor $visitor Visitor to add\n     */\n    public function addVisitor(NodeVisitor $visitor): void {\n        $this->visitors[] = $visitor;\n    }\n\n    /**\n     * Removes an added visitor.\n     */\n    public function removeVisitor(NodeVisitor $visitor): void {\n        $index = array_search($visitor, $this->visitors);\n        if ($index !== false) {\n            array_splice($this->visitors, $index, 1, []);\n        }\n    }\n\n    /**\n     * Traverses an array of nodes using the registered visitors.\n     *\n     * @param Node[] $nodes Array of nodes\n     *\n     * @return Node[] Traversed array of nodes\n     */\n    public function traverse(array $nodes): array {\n        $this->stopTraversal = false;\n\n        foreach ($this->visitors as $visitor) {\n            if (null !== $return = $visitor->beforeTraverse($nodes)) {\n                $nodes = $return;\n            }\n        }\n\n        $nodes = $this->traverseArray($nodes);\n\n        for ($i = \\count($this->visitors) - 1; $i >= 0; --$i) {\n            $visitor = $this->visitors[$i];\n            if (null !== $return = $visitor->afterTraverse($nodes)) {\n                $nodes = $return;\n            }\n        }\n\n        return $nodes;\n    }\n\n    /**\n     * Recursively traverse a node.\n     *\n     * @param Node $node Node to traverse.\n     */\n    protected function traverseNode(Node $node): void {\n        foreach ($node->getSubNodeNames() as $name) {\n            $subNode = $node->$name;\n\n            if (\\is_array($subNode)) {\n                $node->$name = $this->traverseArray($subNode);\n                if ($this->stopTraversal) {\n                    break;\n                }\n\n                continue;\n            }\n\n            if (!$subNode instanceof Node) {\n                continue;\n            }\n\n            $traverseChildren = true;\n            $visitorIndex = -1;\n\n            foreach ($this->visitors as $visitorIndex => $visitor) {\n                $return = $visitor->enterNode($subNode);\n                if (null !== $return) {\n                    if ($return instanceof Node) {\n                        $this->ensureReplacementReasonable($subNode, $return);\n                        $subNode = $node->$name = $return;\n                    } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {\n                        $traverseChildren = false;\n                    } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {\n                        $traverseChildren = false;\n                        break;\n                    } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {\n                        $this->stopTraversal = true;\n                        break 2;\n                    } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {\n                        $node->$name = null;\n                        continue 2;\n                    } else {\n                        throw new \\LogicException(\n                            'enterNode() returned invalid value of type ' . gettype($return)\n                        );\n                    }\n                }\n            }\n\n            if ($traverseChildren) {\n                $this->traverseNode($subNode);\n                if ($this->stopTraversal) {\n                    break;\n                }\n            }\n\n            for (; $visitorIndex >= 0; --$visitorIndex) {\n                $visitor = $this->visitors[$visitorIndex];\n                $return = $visitor->leaveNode($subNode);\n\n                if (null !== $return) {\n                    if ($return instanceof Node) {\n                        $this->ensureReplacementReasonable($subNode, $return);\n                        $subNode = $node->$name = $return;\n                    } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {\n                        $this->stopTraversal = true;\n                        break 2;\n                    } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {\n                        $node->$name = null;\n                        break;\n                    } elseif (\\is_array($return)) {\n                        throw new \\LogicException(\n                            'leaveNode() may only return an array ' .\n                            'if the parent structure is an array'\n                        );\n                    } else {\n                        throw new \\LogicException(\n                            'leaveNode() returned invalid value of type ' . gettype($return)\n                        );\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Recursively traverse array (usually of nodes).\n     *\n     * @param Node[] $nodes Array to traverse\n     *\n     * @return Node[] Result of traversal (may be original array or changed one)\n     */\n    protected function traverseArray(array $nodes): array {\n        $doNodes = [];\n\n        foreach ($nodes as $i => $node) {\n            if (!$node instanceof Node) {\n                if (\\is_array($node)) {\n                    throw new \\LogicException('Invalid node structure: Contains nested arrays');\n                }\n                continue;\n            }\n\n            $traverseChildren = true;\n            $visitorIndex = -1;\n\n            foreach ($this->visitors as $visitorIndex => $visitor) {\n                $return = $visitor->enterNode($node);\n                if (null !== $return) {\n                    if ($return instanceof Node) {\n                        $this->ensureReplacementReasonable($node, $return);\n                        $nodes[$i] = $node = $return;\n                    } elseif (\\is_array($return)) {\n                        $doNodes[] = [$i, $return];\n                        continue 2;\n                    } elseif (NodeVisitor::REMOVE_NODE === $return) {\n                        $doNodes[] = [$i, []];\n                        continue 2;\n                    } elseif (NodeVisitor::DONT_TRAVERSE_CHILDREN === $return) {\n                        $traverseChildren = false;\n                    } elseif (NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN === $return) {\n                        $traverseChildren = false;\n                        break;\n                    } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {\n                        $this->stopTraversal = true;\n                        break 2;\n                    } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {\n                        throw new \\LogicException(\n                            'REPLACE_WITH_NULL can not be used if the parent structure is an array');\n                    } else {\n                        throw new \\LogicException(\n                            'enterNode() returned invalid value of type ' . gettype($return)\n                        );\n                    }\n                }\n            }\n\n            if ($traverseChildren) {\n                $this->traverseNode($node);\n                if ($this->stopTraversal) {\n                    break;\n                }\n            }\n\n            for (; $visitorIndex >= 0; --$visitorIndex) {\n                $visitor = $this->visitors[$visitorIndex];\n                $return = $visitor->leaveNode($node);\n\n                if (null !== $return) {\n                    if ($return instanceof Node) {\n                        $this->ensureReplacementReasonable($node, $return);\n                        $nodes[$i] = $node = $return;\n                    } elseif (\\is_array($return)) {\n                        $doNodes[] = [$i, $return];\n                        break;\n                    } elseif (NodeVisitor::REMOVE_NODE === $return) {\n                        $doNodes[] = [$i, []];\n                        break;\n                    } elseif (NodeVisitor::STOP_TRAVERSAL === $return) {\n                        $this->stopTraversal = true;\n                        break 2;\n                    } elseif (NodeVisitor::REPLACE_WITH_NULL === $return) {\n                        throw new \\LogicException(\n                            'REPLACE_WITH_NULL can not be used if the parent structure is an array');\n                    } else {\n                        throw new \\LogicException(\n                            'leaveNode() returned invalid value of type ' . gettype($return)\n                        );\n                    }\n                }\n            }\n        }\n\n        if (!empty($doNodes)) {\n            while (list($i, $replace) = array_pop($doNodes)) {\n                array_splice($nodes, $i, 1, $replace);\n            }\n        }\n\n        return $nodes;\n    }\n\n    private function ensureReplacementReasonable(Node $old, Node $new): void {\n        if ($old instanceof Node\\Stmt && $new instanceof Node\\Expr) {\n            throw new \\LogicException(\n                \"Trying to replace statement ({$old->getType()}) \" .\n                \"with expression ({$new->getType()}). Are you missing a \" .\n                \"Stmt_Expression wrapper?\"\n            );\n        }\n\n        if ($old instanceof Node\\Expr && $new instanceof Node\\Stmt) {\n            throw new \\LogicException(\n                \"Trying to replace expression ({$old->getType()}) \" .\n                \"with statement ({$new->getType()})\"\n            );\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeTraverserInterface.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface NodeTraverserInterface {\n    /**\n     * Adds a visitor.\n     *\n     * @param NodeVisitor $visitor Visitor to add\n     */\n    public function addVisitor(NodeVisitor $visitor): void;\n\n    /**\n     * Removes an added visitor.\n     */\n    public function removeVisitor(NodeVisitor $visitor): void;\n\n    /**\n     * Traverses an array of nodes using the registered visitors.\n     *\n     * @param Node[] $nodes Array of nodes\n     *\n     * @return Node[] Traversed array of nodes\n     */\n    public function traverse(array $nodes): array;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CloningVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\n\n/**\n * Visitor cloning all nodes and linking to the original nodes using an attribute.\n *\n * This visitor is required to perform format-preserving pretty prints.\n */\nclass CloningVisitor extends NodeVisitorAbstract {\n    public function enterNode(Node $origNode) {\n        $node = clone $origNode;\n        $node->setAttribute('origNode', $origNode);\n        return $node;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/CommentAnnotatingVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Comment;\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\nuse PhpParser\\Token;\n\nclass CommentAnnotatingVisitor extends NodeVisitorAbstract {\n    /** @var int Last seen token start position */\n    private int $pos = 0;\n    /** @var Token[] Token array */\n    private array $tokens;\n    /** @var list<int> Token positions of comments */\n    private array $commentPositions = [];\n\n    /**\n     * Create a comment annotation visitor.\n     *\n     * @param Token[] $tokens Token array\n     */\n    public function __construct(array $tokens) {\n        $this->tokens = $tokens;\n\n        // Collect positions of comments. We use this to avoid traversing parts of the AST where\n        // there are no comments.\n        foreach ($tokens as $i => $token) {\n            if ($token->id === \\T_COMMENT || $token->id === \\T_DOC_COMMENT) {\n                $this->commentPositions[] = $i;\n            }\n        }\n    }\n\n    public function enterNode(Node $node) {\n        $nextCommentPos = current($this->commentPositions);\n        if ($nextCommentPos === false) {\n            // No more comments.\n            return self::STOP_TRAVERSAL;\n        }\n\n        $oldPos = $this->pos;\n        $this->pos = $pos = $node->getStartTokenPos();\n        if ($nextCommentPos > $oldPos && $nextCommentPos < $pos) {\n            $comments = [];\n            while (--$pos >= $oldPos) {\n                $token = $this->tokens[$pos];\n                if ($token->id === \\T_DOC_COMMENT) {\n                    $comments[] = new Comment\\Doc(\n                        $token->text, $token->line, $token->pos, $pos,\n                        $token->getEndLine(), $token->getEndPos() - 1, $pos);\n                    continue;\n                }\n                if ($token->id === \\T_COMMENT) {\n                    $comments[] = new Comment(\n                        $token->text, $token->line, $token->pos, $pos,\n                        $token->getEndLine(), $token->getEndPos() - 1, $pos);\n                    continue;\n                }\n                if ($token->id !== \\T_WHITESPACE) {\n                    break;\n                }\n            }\n            if (!empty($comments)) {\n                $node->setAttribute('comments', array_reverse($comments));\n            }\n\n            do {\n                $nextCommentPos = next($this->commentPositions);\n            } while ($nextCommentPos !== false && $nextCommentPos < $this->pos);\n        }\n\n        $endPos = $node->getEndTokenPos();\n        if ($nextCommentPos > $endPos) {\n            // Skip children if there are no comments located inside this node.\n            $this->pos = $endPos;\n            return self::DONT_TRAVERSE_CHILDREN;\n        }\n\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FindingVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\n\n/**\n * This visitor can be used to find and collect all nodes satisfying some criterion determined by\n * a filter callback.\n */\nclass FindingVisitor extends NodeVisitorAbstract {\n    /** @var callable Filter callback */\n    protected $filterCallback;\n    /** @var list<Node> Found nodes */\n    protected array $foundNodes;\n\n    public function __construct(callable $filterCallback) {\n        $this->filterCallback = $filterCallback;\n    }\n\n    /**\n     * Get found nodes satisfying the filter callback.\n     *\n     * Nodes are returned in pre-order.\n     *\n     * @return list<Node> Found nodes\n     */\n    public function getFoundNodes(): array {\n        return $this->foundNodes;\n    }\n\n    public function beforeTraverse(array $nodes): ?array {\n        $this->foundNodes = [];\n\n        return null;\n    }\n\n    public function enterNode(Node $node) {\n        $filterCallback = $this->filterCallback;\n        if ($filterCallback($node)) {\n            $this->foundNodes[] = $node;\n        }\n\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/FirstFindingVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitor;\nuse PhpParser\\NodeVisitorAbstract;\n\n/**\n * This visitor can be used to find the first node satisfying some criterion determined by\n * a filter callback.\n */\nclass FirstFindingVisitor extends NodeVisitorAbstract {\n    /** @var callable Filter callback */\n    protected $filterCallback;\n    /** @var null|Node Found node */\n    protected ?Node $foundNode;\n\n    public function __construct(callable $filterCallback) {\n        $this->filterCallback = $filterCallback;\n    }\n\n    /**\n     * Get found node satisfying the filter callback.\n     *\n     * Returns null if no node satisfies the filter callback.\n     *\n     * @return null|Node Found node (or null if not found)\n     */\n    public function getFoundNode(): ?Node {\n        return $this->foundNode;\n    }\n\n    public function beforeTraverse(array $nodes): ?array {\n        $this->foundNode = null;\n\n        return null;\n    }\n\n    public function enterNode(Node $node) {\n        $filterCallback = $this->filterCallback;\n        if ($filterCallback($node)) {\n            $this->foundNode = $node;\n            return NodeVisitor::STOP_TRAVERSAL;\n        }\n\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NameResolver.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\ErrorHandler;\nuse PhpParser\\NameContext;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Name\\FullyQualified;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\NodeVisitorAbstract;\n\nclass NameResolver extends NodeVisitorAbstract {\n    /** @var NameContext Naming context */\n    protected NameContext $nameContext;\n\n    /** @var bool Whether to preserve original names */\n    protected bool $preserveOriginalNames;\n\n    /** @var bool Whether to replace resolved nodes in place, or to add resolvedNode attributes */\n    protected bool $replaceNodes;\n\n    /**\n     * Constructs a name resolution visitor.\n     *\n     * Options:\n     *  * preserveOriginalNames (default false): An \"originalName\" attribute will be added to\n     *    all name nodes that underwent resolution.\n     *  * replaceNodes (default true): Resolved names are replaced in-place. Otherwise, a\n     *    resolvedName attribute is added. (Names that cannot be statically resolved receive a\n     *    namespacedName attribute, as usual.)\n     *\n     * @param ErrorHandler|null $errorHandler Error handler\n     * @param array{preserveOriginalNames?: bool, replaceNodes?: bool} $options Options\n     */\n    public function __construct(?ErrorHandler $errorHandler = null, array $options = []) {\n        $this->nameContext = new NameContext($errorHandler ?? new ErrorHandler\\Throwing());\n        $this->preserveOriginalNames = $options['preserveOriginalNames'] ?? false;\n        $this->replaceNodes = $options['replaceNodes'] ?? true;\n    }\n\n    /**\n     * Get name resolution context.\n     */\n    public function getNameContext(): NameContext {\n        return $this->nameContext;\n    }\n\n    public function beforeTraverse(array $nodes): ?array {\n        $this->nameContext->startNamespace();\n        return null;\n    }\n\n    public function enterNode(Node $node) {\n        if ($node instanceof Stmt\\Namespace_) {\n            $this->nameContext->startNamespace($node->name);\n        } elseif ($node instanceof Stmt\\Use_) {\n            foreach ($node->uses as $use) {\n                $this->addAlias($use, $node->type, null);\n            }\n        } elseif ($node instanceof Stmt\\GroupUse) {\n            foreach ($node->uses as $use) {\n                $this->addAlias($use, $node->type, $node->prefix);\n            }\n        } elseif ($node instanceof Stmt\\Class_) {\n            if (null !== $node->extends) {\n                $node->extends = $this->resolveClassName($node->extends);\n            }\n\n            foreach ($node->implements as &$interface) {\n                $interface = $this->resolveClassName($interface);\n            }\n\n            $this->resolveAttrGroups($node);\n            if (null !== $node->name) {\n                $this->addNamespacedName($node);\n            } else {\n                $node->namespacedName = null;\n            }\n        } elseif ($node instanceof Stmt\\Interface_) {\n            foreach ($node->extends as &$interface) {\n                $interface = $this->resolveClassName($interface);\n            }\n\n            $this->resolveAttrGroups($node);\n            $this->addNamespacedName($node);\n        } elseif ($node instanceof Stmt\\Enum_) {\n            foreach ($node->implements as &$interface) {\n                $interface = $this->resolveClassName($interface);\n            }\n\n            $this->resolveAttrGroups($node);\n            $this->addNamespacedName($node);\n        } elseif ($node instanceof Stmt\\Trait_) {\n            $this->resolveAttrGroups($node);\n            $this->addNamespacedName($node);\n        } elseif ($node instanceof Stmt\\Function_) {\n            $this->resolveSignature($node);\n            $this->resolveAttrGroups($node);\n            $this->addNamespacedName($node);\n        } elseif ($node instanceof Stmt\\ClassMethod\n                  || $node instanceof Expr\\Closure\n                  || $node instanceof Expr\\ArrowFunction\n        ) {\n            $this->resolveSignature($node);\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Stmt\\Property) {\n            if (null !== $node->type) {\n                $node->type = $this->resolveType($node->type);\n            }\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Node\\PropertyHook) {\n            foreach ($node->params as $param) {\n                $param->type = $this->resolveType($param->type);\n                $this->resolveAttrGroups($param);\n            }\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Stmt\\Const_) {\n            foreach ($node->consts as $const) {\n                $this->addNamespacedName($const);\n            }\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Stmt\\ClassConst) {\n            if (null !== $node->type) {\n                $node->type = $this->resolveType($node->type);\n            }\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Stmt\\EnumCase) {\n            $this->resolveAttrGroups($node);\n        } elseif ($node instanceof Expr\\StaticCall\n                  || $node instanceof Expr\\StaticPropertyFetch\n                  || $node instanceof Expr\\ClassConstFetch\n                  || $node instanceof Expr\\New_\n                  || $node instanceof Expr\\Instanceof_\n        ) {\n            if ($node->class instanceof Name) {\n                $node->class = $this->resolveClassName($node->class);\n            }\n        } elseif ($node instanceof Stmt\\Catch_) {\n            foreach ($node->types as &$type) {\n                $type = $this->resolveClassName($type);\n            }\n        } elseif ($node instanceof Expr\\FuncCall) {\n            if ($node->name instanceof Name) {\n                $node->name = $this->resolveName($node->name, Stmt\\Use_::TYPE_FUNCTION);\n            }\n        } elseif ($node instanceof Expr\\ConstFetch) {\n            $node->name = $this->resolveName($node->name, Stmt\\Use_::TYPE_CONSTANT);\n        } elseif ($node instanceof Stmt\\TraitUse) {\n            foreach ($node->traits as &$trait) {\n                $trait = $this->resolveClassName($trait);\n            }\n\n            foreach ($node->adaptations as $adaptation) {\n                if (null !== $adaptation->trait) {\n                    $adaptation->trait = $this->resolveClassName($adaptation->trait);\n                }\n\n                if ($adaptation instanceof Stmt\\TraitUseAdaptation\\Precedence) {\n                    foreach ($adaptation->insteadof as &$insteadof) {\n                        $insteadof = $this->resolveClassName($insteadof);\n                    }\n                }\n            }\n        }\n\n        return null;\n    }\n\n    /** @param Stmt\\Use_::TYPE_* $type */\n    private function addAlias(Node\\UseItem $use, int $type, ?Name $prefix = null): void {\n        // Add prefix for group uses\n        $name = $prefix ? Name::concat($prefix, $use->name) : $use->name;\n        // Type is determined either by individual element or whole use declaration\n        $type |= $use->type;\n\n        $this->nameContext->addAlias(\n            $name, (string) $use->getAlias(), $type, $use->getAttributes()\n        );\n    }\n\n    /** @param Stmt\\Function_|Stmt\\ClassMethod|Expr\\Closure|Expr\\ArrowFunction $node */\n    private function resolveSignature($node): void {\n        foreach ($node->params as $param) {\n            $param->type = $this->resolveType($param->type);\n            $this->resolveAttrGroups($param);\n        }\n        $node->returnType = $this->resolveType($node->returnType);\n    }\n\n    /**\n     * @template T of Node\\Identifier|Name|Node\\ComplexType|null\n     * @param T $node\n     * @return T\n     */\n    private function resolveType(?Node $node): ?Node {\n        if ($node instanceof Name) {\n            return $this->resolveClassName($node);\n        }\n        if ($node instanceof Node\\NullableType) {\n            $node->type = $this->resolveType($node->type);\n            return $node;\n        }\n        if ($node instanceof Node\\UnionType || $node instanceof Node\\IntersectionType) {\n            foreach ($node->types as &$type) {\n                $type = $this->resolveType($type);\n            }\n            return $node;\n        }\n        return $node;\n    }\n\n    /**\n     * Resolve name, according to name resolver options.\n     *\n     * @param Name $name Function or constant name to resolve\n     * @param Stmt\\Use_::TYPE_* $type One of Stmt\\Use_::TYPE_*\n     *\n     * @return Name Resolved name, or original name with attribute\n     */\n    protected function resolveName(Name $name, int $type): Name {\n        if (!$this->replaceNodes) {\n            $resolvedName = $this->nameContext->getResolvedName($name, $type);\n            if (null !== $resolvedName) {\n                $name->setAttribute('resolvedName', $resolvedName);\n            } else {\n                $name->setAttribute('namespacedName', FullyQualified::concat(\n                    $this->nameContext->getNamespace(), $name, $name->getAttributes()));\n            }\n            return $name;\n        }\n\n        if ($this->preserveOriginalNames) {\n            // Save the original name\n            $originalName = $name;\n            $name = clone $originalName;\n            $name->setAttribute('originalName', $originalName);\n        }\n\n        $resolvedName = $this->nameContext->getResolvedName($name, $type);\n        if (null !== $resolvedName) {\n            return $resolvedName;\n        }\n\n        // unqualified names inside a namespace cannot be resolved at compile-time\n        // add the namespaced version of the name as an attribute\n        $name->setAttribute('namespacedName', FullyQualified::concat(\n            $this->nameContext->getNamespace(), $name, $name->getAttributes()));\n        return $name;\n    }\n\n    protected function resolveClassName(Name $name): Name {\n        return $this->resolveName($name, Stmt\\Use_::TYPE_NORMAL);\n    }\n\n    protected function addNamespacedName(Node $node): void {\n        $node->namespacedName = Name::concat(\n            $this->nameContext->getNamespace(), (string) $node->name);\n    }\n\n    protected function resolveAttrGroups(Node $node): void {\n        foreach ($node->attrGroups as $attrGroup) {\n            foreach ($attrGroup->attrs as $attr) {\n                $attr->name = $this->resolveClassName($attr->name);\n            }\n        }\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/NodeConnectingVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\n\n/**\n * Visitor that connects a child node to its parent node\n * as well as its sibling nodes.\n *\n * With <code>$weakReferences=false</code> on the child node, the parent node can be accessed through\n * <code>$node->getAttribute('parent')</code>, the previous\n * node can be accessed through <code>$node->getAttribute('previous')</code>,\n * and the next node can be accessed through <code>$node->getAttribute('next')</code>.\n *\n * With <code>$weakReferences=true</code> attribute names are prefixed by \"weak_\", e.g. \"weak_parent\".\n */\nfinal class NodeConnectingVisitor extends NodeVisitorAbstract {\n    /**\n     * @var Node[]\n     */\n    private array $stack = [];\n\n    /**\n     * @var ?Node\n     */\n    private $previous;\n\n    private bool $weakReferences;\n\n    public function __construct(bool $weakReferences = false) {\n        $this->weakReferences = $weakReferences;\n    }\n\n    public function beforeTraverse(array $nodes) {\n        $this->stack    = [];\n        $this->previous = null;\n    }\n\n    public function enterNode(Node $node) {\n        if (!empty($this->stack)) {\n            $parent = $this->stack[count($this->stack) - 1];\n            if ($this->weakReferences) {\n                $node->setAttribute('weak_parent', \\WeakReference::create($parent));\n            } else {\n                $node->setAttribute('parent', $parent);\n            }\n        }\n\n        if ($this->previous !== null) {\n            if (\n                $this->weakReferences\n            ) {\n                if ($this->previous->getAttribute('weak_parent') === $node->getAttribute('weak_parent')) {\n                    $node->setAttribute('weak_previous', \\WeakReference::create($this->previous));\n                    $this->previous->setAttribute('weak_next', \\WeakReference::create($node));\n                }\n            } elseif ($this->previous->getAttribute('parent') === $node->getAttribute('parent')) {\n                $node->setAttribute('previous', $this->previous);\n                $this->previous->setAttribute('next', $node);\n            }\n        }\n\n        $this->stack[] = $node;\n    }\n\n    public function leaveNode(Node $node) {\n        $this->previous = $node;\n\n        array_pop($this->stack);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor/ParentConnectingVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\NodeVisitor;\n\nuse PhpParser\\Node;\nuse PhpParser\\NodeVisitorAbstract;\n\nuse function array_pop;\nuse function count;\n\n/**\n * Visitor that connects a child node to its parent node.\n *\n * With <code>$weakReferences=false</code> on the child node, the parent node can be accessed through\n * <code>$node->getAttribute('parent')</code>.\n *\n * With <code>$weakReferences=true</code> the attribute name is \"weak_parent\" instead.\n */\nfinal class ParentConnectingVisitor extends NodeVisitorAbstract {\n    /**\n     * @var Node[]\n     */\n    private array $stack = [];\n\n    private bool $weakReferences;\n\n    public function __construct(bool $weakReferences = false) {\n        $this->weakReferences = $weakReferences;\n    }\n\n    public function beforeTraverse(array $nodes) {\n        $this->stack = [];\n    }\n\n    public function enterNode(Node $node) {\n        if (!empty($this->stack)) {\n            $parent = $this->stack[count($this->stack) - 1];\n            if ($this->weakReferences) {\n                $node->setAttribute('weak_parent', \\WeakReference::create($parent));\n            } else {\n                $node->setAttribute('parent', $parent);\n            }\n        }\n\n        $this->stack[] = $node;\n    }\n\n    public function leaveNode(Node $node) {\n        array_pop($this->stack);\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitor.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface NodeVisitor {\n    /**\n     * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes\n     * of the current node will not be traversed for any visitors.\n     *\n     * For subsequent visitors enterNode() will still be called on the current\n     * node and leaveNode() will also be invoked for the current node.\n     */\n    public const DONT_TRAVERSE_CHILDREN = 1;\n\n    /**\n     * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns\n     * STOP_TRAVERSAL, traversal is aborted.\n     *\n     * The afterTraverse() method will still be invoked.\n     */\n    public const STOP_TRAVERSAL = 2;\n\n    /**\n     * If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs\n     * in an array, it will be removed from the array.\n     *\n     * For subsequent visitors leaveNode() will still be invoked for the\n     * removed node.\n     */\n    public const REMOVE_NODE = 3;\n\n    /**\n     * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes\n     * of the current node will not be traversed for any visitors.\n     *\n     * For subsequent visitors enterNode() will not be called as well.\n     * leaveNode() will be invoked for visitors that has enterNode() method invoked.\n     */\n    public const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;\n\n    /**\n     * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns REPLACE_WITH_NULL,\n     * the node will be replaced with null. This is not a legal return value if the node is part\n     * of an array, rather than another node.\n     */\n    public const REPLACE_WITH_NULL = 5;\n\n    /**\n     * Called once before traversal.\n     *\n     * Return value semantics:\n     *  * null:      $nodes stays as-is\n     *  * otherwise: $nodes is set to the return value\n     *\n     * @param Node[] $nodes Array of nodes\n     *\n     * @return null|Node[] Array of nodes\n     */\n    public function beforeTraverse(array $nodes);\n\n    /**\n     * Called when entering a node.\n     *\n     * Return value semantics:\n     *  * null\n     *        => $node stays as-is\n     *  * array (of Nodes)\n     *        => The return value is merged into the parent array (at the position of the $node)\n     *  * NodeVisitor::REMOVE_NODE\n     *        => $node is removed from the parent array\n     *  * NodeVisitor::REPLACE_WITH_NULL\n     *        => $node is replaced with null\n     *  * NodeVisitor::DONT_TRAVERSE_CHILDREN\n     *        => Children of $node are not traversed. $node stays as-is\n     *  * NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN\n     *        => Further visitors for the current node are skipped, and its children are not\n     *           traversed. $node stays as-is.\n     *  * NodeVisitor::STOP_TRAVERSAL\n     *        => Traversal is aborted. $node stays as-is\n     *  * otherwise\n     *        => $node is set to the return value\n     *\n     * @param Node $node Node\n     *\n     * @return null|int|Node|Node[] Replacement node (or special return value)\n     */\n    public function enterNode(Node $node);\n\n    /**\n     * Called when leaving a node.\n     *\n     * Return value semantics:\n     *  * null\n     *        => $node stays as-is\n     *  * NodeVisitor::REMOVE_NODE\n     *        => $node is removed from the parent array\n     *  * NodeVisitor::REPLACE_WITH_NULL\n     *        => $node is replaced with null\n     *  * NodeVisitor::STOP_TRAVERSAL\n     *        => Traversal is aborted. $node stays as-is\n     *  * array (of Nodes)\n     *        => The return value is merged into the parent array (at the position of the $node)\n     *  * otherwise\n     *        => $node is set to the return value\n     *\n     * @param Node $node Node\n     *\n     * @return null|int|Node|Node[] Replacement node (or special return value)\n     */\n    public function leaveNode(Node $node);\n\n    /**\n     * Called once after traversal.\n     *\n     * Return value semantics:\n     *  * null:      $nodes stays as-is\n     *  * otherwise: $nodes is set to the return value\n     *\n     * @param Node[] $nodes Array of nodes\n     *\n     * @return null|Node[] Array of nodes\n     */\n    public function afterTraverse(array $nodes);\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/NodeVisitorAbstract.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\n/**\n * @codeCoverageIgnore\n */\nabstract class NodeVisitorAbstract implements NodeVisitor {\n    public function beforeTraverse(array $nodes) {\n        return null;\n    }\n\n    public function enterNode(Node $node) {\n        return null;\n    }\n\n    public function leaveNode(Node $node) {\n        return null;\n    }\n\n    public function afterTraverse(array $nodes) {\n        return null;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Parser/Php7.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Parser;\n\nuse PhpParser\\Error;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Scalar;\nuse PhpParser\\Node\\Stmt;\n\n/* This is an automatically GENERATED file, which should not be manually edited.\n * Instead edit one of the following:\n *  * the grammar file grammar/php.y\n *  * the skeleton file grammar/parser.template\n *  * the preprocessing script grammar/rebuildParsers.php\n */\nclass Php7 extends \\PhpParser\\ParserAbstract\n{\n    public const YYERRTOK = 256;\n    public const T_VOID_CAST = 257;\n    public const T_THROW = 258;\n    public const T_INCLUDE = 259;\n    public const T_INCLUDE_ONCE = 260;\n    public const T_EVAL = 261;\n    public const T_REQUIRE = 262;\n    public const T_REQUIRE_ONCE = 263;\n    public const T_LOGICAL_OR = 264;\n    public const T_LOGICAL_XOR = 265;\n    public const T_LOGICAL_AND = 266;\n    public const T_PRINT = 267;\n    public const T_YIELD = 268;\n    public const T_DOUBLE_ARROW = 269;\n    public const T_YIELD_FROM = 270;\n    public const T_PLUS_EQUAL = 271;\n    public const T_MINUS_EQUAL = 272;\n    public const T_MUL_EQUAL = 273;\n    public const T_DIV_EQUAL = 274;\n    public const T_CONCAT_EQUAL = 275;\n    public const T_MOD_EQUAL = 276;\n    public const T_AND_EQUAL = 277;\n    public const T_OR_EQUAL = 278;\n    public const T_XOR_EQUAL = 279;\n    public const T_SL_EQUAL = 280;\n    public const T_SR_EQUAL = 281;\n    public const T_POW_EQUAL = 282;\n    public const T_COALESCE_EQUAL = 283;\n    public const T_COALESCE = 284;\n    public const T_BOOLEAN_OR = 285;\n    public const T_BOOLEAN_AND = 286;\n    public const T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG = 287;\n    public const T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG = 288;\n    public const T_IS_EQUAL = 289;\n    public const T_IS_NOT_EQUAL = 290;\n    public const T_IS_IDENTICAL = 291;\n    public const T_IS_NOT_IDENTICAL = 292;\n    public const T_SPACESHIP = 293;\n    public const T_IS_SMALLER_OR_EQUAL = 294;\n    public const T_IS_GREATER_OR_EQUAL = 295;\n    public const T_SL = 296;\n    public const T_SR = 297;\n    public const T_INSTANCEOF = 298;\n    public const T_INC = 299;\n    public const T_DEC = 300;\n    public const T_INT_CAST = 301;\n    public const T_DOUBLE_CAST = 302;\n    public const T_STRING_CAST = 303;\n    public const T_ARRAY_CAST = 304;\n    public const T_OBJECT_CAST = 305;\n    public const T_BOOL_CAST = 306;\n    public const T_UNSET_CAST = 307;\n    public const T_POW = 308;\n    public const T_NEW = 309;\n    public const T_CLONE = 310;\n    public const T_EXIT = 311;\n    public const T_IF = 312;\n    public const T_ELSEIF = 313;\n    public const T_ELSE = 314;\n    public const T_ENDIF = 315;\n    public const T_LNUMBER = 316;\n    public const T_DNUMBER = 317;\n    public const T_STRING = 318;\n    public const T_STRING_VARNAME = 319;\n    public const T_VARIABLE = 320;\n    public const T_NUM_STRING = 321;\n    public const T_INLINE_HTML = 322;\n    public const T_ENCAPSED_AND_WHITESPACE = 323;\n    public const T_CONSTANT_ENCAPSED_STRING = 324;\n    public const T_ECHO = 325;\n    public const T_DO = 326;\n    public const T_WHILE = 327;\n    public const T_ENDWHILE = 328;\n    public const T_FOR = 329;\n    public const T_ENDFOR = 330;\n    public const T_FOREACH = 331;\n    public const T_ENDFOREACH = 332;\n    public const T_DECLARE = 333;\n    public const T_ENDDECLARE = 334;\n    public const T_AS = 335;\n    public const T_SWITCH = 336;\n    public const T_MATCH = 337;\n    public const T_ENDSWITCH = 338;\n    public const T_CASE = 339;\n    public const T_DEFAULT = 340;\n    public const T_BREAK = 341;\n    public const T_CONTINUE = 342;\n    public const T_GOTO = 343;\n    public const T_FUNCTION = 344;\n    public const T_FN = 345;\n    public const T_CONST = 346;\n    public const T_RETURN = 347;\n    public const T_TRY = 348;\n    public const T_CATCH = 349;\n    public const T_FINALLY = 350;\n    public const T_USE = 351;\n    public const T_INSTEADOF = 352;\n    public const T_GLOBAL = 353;\n    public const T_STATIC = 354;\n    public const T_ABSTRACT = 355;\n    public const T_FINAL = 356;\n    public const T_PRIVATE = 357;\n    public const T_PROTECTED = 358;\n    public const T_PUBLIC = 359;\n    public const T_READONLY = 360;\n    public const T_PUBLIC_SET = 361;\n    public const T_PROTECTED_SET = 362;\n    public const T_PRIVATE_SET = 363;\n    public const T_VAR = 364;\n    public const T_UNSET = 365;\n    public const T_ISSET = 366;\n    public const T_EMPTY = 367;\n    public const T_HALT_COMPILER = 368;\n    public const T_CLASS = 369;\n    public const T_TRAIT = 370;\n    public const T_INTERFACE = 371;\n    public const T_ENUM = 372;\n    public const T_EXTENDS = 373;\n    public const T_IMPLEMENTS = 374;\n    public const T_OBJECT_OPERATOR = 375;\n    public const T_NULLSAFE_OBJECT_OPERATOR = 376;\n    public const T_LIST = 377;\n    public const T_ARRAY = 378;\n    public const T_CALLABLE = 379;\n    public const T_CLASS_C = 380;\n    public const T_TRAIT_C = 381;\n    public const T_METHOD_C = 382;\n    public const T_FUNC_C = 383;\n    public const T_PROPERTY_C = 384;\n    public const T_LINE = 385;\n    public const T_FILE = 386;\n    public const T_START_HEREDOC = 387;\n    public const T_END_HEREDOC = 388;\n    public const T_DOLLAR_OPEN_CURLY_BRACES = 389;\n    public const T_CURLY_OPEN = 390;\n    public const T_PAAMAYIM_NEKUDOTAYIM = 391;\n    public const T_NAMESPACE = 392;\n    public const T_NS_C = 393;\n    public const T_DIR = 394;\n    public const T_NS_SEPARATOR = 395;\n    public const T_ELLIPSIS = 396;\n    public const T_NAME_FULLY_QUALIFIED = 397;\n    public const T_NAME_QUALIFIED = 398;\n    public const T_NAME_RELATIVE = 399;\n    public const T_ATTRIBUTE = 400;\n\n    protected int $tokenToSymbolMapSize = 401;\n    protected int $actionTableSize = 1620;\n    protected int $gotoTableSize = 696;\n\n    protected int $invalidSymbol = 173;\n    protected int $errorSymbol = 1;\n    protected int $defaultAction = -32766;\n    protected int $unexpectedTokenRule = 32767;\n\n    protected int $YY2TBLSTATE = 444;\n    protected int $numNonLeafStates = 751;\n\n    protected array $symbolToName = array(\n        \"EOF\",\n        \"error\",\n        \"T_VOID_CAST\",\n        \"T_THROW\",\n        \"T_INCLUDE\",\n        \"T_INCLUDE_ONCE\",\n        \"T_EVAL\",\n        \"T_REQUIRE\",\n        \"T_REQUIRE_ONCE\",\n        \"','\",\n        \"T_LOGICAL_OR\",\n        \"T_LOGICAL_XOR\",\n        \"T_LOGICAL_AND\",\n        \"T_PRINT\",\n        \"T_YIELD\",\n        \"T_DOUBLE_ARROW\",\n        \"T_YIELD_FROM\",\n        \"'='\",\n        \"T_PLUS_EQUAL\",\n        \"T_MINUS_EQUAL\",\n        \"T_MUL_EQUAL\",\n        \"T_DIV_EQUAL\",\n        \"T_CONCAT_EQUAL\",\n        \"T_MOD_EQUAL\",\n        \"T_AND_EQUAL\",\n        \"T_OR_EQUAL\",\n        \"T_XOR_EQUAL\",\n        \"T_SL_EQUAL\",\n        \"T_SR_EQUAL\",\n        \"T_POW_EQUAL\",\n        \"T_COALESCE_EQUAL\",\n        \"'?'\",\n        \"':'\",\n        \"T_COALESCE\",\n        \"T_BOOLEAN_OR\",\n        \"T_BOOLEAN_AND\",\n        \"'|'\",\n        \"'^'\",\n        \"T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG\",\n        \"T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG\",\n        \"T_IS_EQUAL\",\n        \"T_IS_NOT_EQUAL\",\n        \"T_IS_IDENTICAL\",\n        \"T_IS_NOT_IDENTICAL\",\n        \"T_SPACESHIP\",\n        \"'<'\",\n        \"T_IS_SMALLER_OR_EQUAL\",\n        \"'>'\",\n        \"T_IS_GREATER_OR_EQUAL\",\n        \"T_SL\",\n        \"T_SR\",\n        \"'+'\",\n        \"'-'\",\n        \"'.'\",\n        \"'*'\",\n        \"'/'\",\n        \"'%'\",\n        \"'!'\",\n        \"T_INSTANCEOF\",\n        \"'~'\",\n        \"T_INC\",\n        \"T_DEC\",\n        \"T_INT_CAST\",\n        \"T_DOUBLE_CAST\",\n        \"T_STRING_CAST\",\n        \"T_ARRAY_CAST\",\n        \"T_OBJECT_CAST\",\n        \"T_BOOL_CAST\",\n        \"T_UNSET_CAST\",\n        \"'@'\",\n        \"T_POW\",\n        \"'['\",\n        \"T_NEW\",\n        \"T_CLONE\",\n        \"T_EXIT\",\n        \"T_IF\",\n        \"T_ELSEIF\",\n        \"T_ELSE\",\n        \"T_ENDIF\",\n        \"T_LNUMBER\",\n        \"T_DNUMBER\",\n        \"T_STRING\",\n        \"T_STRING_VARNAME\",\n        \"T_VARIABLE\",\n        \"T_NUM_STRING\",\n        \"T_INLINE_HTML\",\n        \"T_ENCAPSED_AND_WHITESPACE\",\n        \"T_CONSTANT_ENCAPSED_STRING\",\n        \"T_ECHO\",\n        \"T_DO\",\n        \"T_WHILE\",\n        \"T_ENDWHILE\",\n        \"T_FOR\",\n        \"T_ENDFOR\",\n        \"T_FOREACH\",\n        \"T_ENDFOREACH\",\n        \"T_DECLARE\",\n        \"T_ENDDECLARE\",\n        \"T_AS\",\n        \"T_SWITCH\",\n        \"T_MATCH\",\n        \"T_ENDSWITCH\",\n        \"T_CASE\",\n        \"T_DEFAULT\",\n        \"T_BREAK\",\n        \"T_CONTINUE\",\n        \"T_GOTO\",\n        \"T_FUNCTION\",\n        \"T_FN\",\n        \"T_CONST\",\n        \"T_RETURN\",\n        \"T_TRY\",\n        \"T_CATCH\",\n        \"T_FINALLY\",\n        \"T_USE\",\n        \"T_INSTEADOF\",\n        \"T_GLOBAL\",\n        \"T_STATIC\",\n        \"T_ABSTRACT\",\n        \"T_FINAL\",\n        \"T_PRIVATE\",\n        \"T_PROTECTED\",\n        \"T_PUBLIC\",\n        \"T_READONLY\",\n        \"T_PUBLIC_SET\",\n        \"T_PROTECTED_SET\",\n        \"T_PRIVATE_SET\",\n        \"T_VAR\",\n        \"T_UNSET\",\n        \"T_ISSET\",\n        \"T_EMPTY\",\n        \"T_HALT_COMPILER\",\n        \"T_CLASS\",\n        \"T_TRAIT\",\n        \"T_INTERFACE\",\n        \"T_ENUM\",\n        \"T_EXTENDS\",\n        \"T_IMPLEMENTS\",\n        \"T_OBJECT_OPERATOR\",\n        \"T_NULLSAFE_OBJECT_OPERATOR\",\n        \"T_LIST\",\n        \"T_ARRAY\",\n        \"T_CALLABLE\",\n        \"T_CLASS_C\",\n        \"T_TRAIT_C\",\n        \"T_METHOD_C\",\n        \"T_FUNC_C\",\n        \"T_PROPERTY_C\",\n        \"T_LINE\",\n        \"T_FILE\",\n        \"T_START_HEREDOC\",\n        \"T_END_HEREDOC\",\n        \"T_DOLLAR_OPEN_CURLY_BRACES\",\n        \"T_CURLY_OPEN\",\n        \"T_PAAMAYIM_NEKUDOTAYIM\",\n        \"T_NAMESPACE\",\n        \"T_NS_C\",\n        \"T_DIR\",\n        \"T_NS_SEPARATOR\",\n        \"T_ELLIPSIS\",\n        \"T_NAME_FULLY_QUALIFIED\",\n        \"T_NAME_QUALIFIED\",\n        \"T_NAME_RELATIVE\",\n        \"T_ATTRIBUTE\",\n        \"';'\",\n        \"']'\",\n        \"'('\",\n        \"')'\",\n        \"'{'\",\n        \"'}'\",\n        \"'`'\",\n        \"'\\\"'\",\n        \"'$'\"\n    );\n\n    protected array $tokenToSymbol = array(\n            0,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,   57,  171,  173,  172,   56,  173,  173,\n          166,  167,   54,   51,    9,   52,   53,   55,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,   32,  164,\n           45,   17,   47,   31,   69,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,   71,  173,  165,   37,  173,  170,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  168,   36,  169,   59,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,  173,  173,  173,  173,\n          173,  173,  173,  173,  173,  173,    1,    2,    3,    4,\n            5,    6,    7,    8,   10,   11,   12,   13,   14,   15,\n           16,   18,   19,   20,   21,   22,   23,   24,   25,   26,\n           27,   28,   29,   30,   33,   34,   35,   38,   39,   40,\n           41,   42,   43,   44,   46,   48,   49,   50,   58,   60,\n           61,   62,   63,   64,   65,   66,   67,   68,   70,   72,\n           73,   74,   75,   76,   77,   78,   79,   80,   81,   82,\n           83,   84,   85,   86,   87,   88,   89,   90,   91,   92,\n           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,\n          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,\n          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,\n          123,  124,  125,  126,  127,  128,  129,  130,  131,  132,\n          133,  134,  135,  136,  137,  138,  139,  140,  141,  142,\n          143,  144,  145,  146,  147,  148,  149,  150,  151,  152,\n          153,  154,  155,  156,  157,  158,  159,  160,  161,  162,\n          163\n    );\n\n    protected array $action = array(\n          134,  135,  136,  574,  137,  138, 1046,  763,  764,  765,\n          139,   41,  387,  388,  447,  336,-32766,-32766,-32766, -628,\n          838,  494,  432,    0,  875, -625,  876, -628, 1092, 1352,\n        -32766,-32766,-32766, -625, -338,  757,  756,-32766,    4,-32766,\n        -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,\n        -32767,-32766, -195,-32766,-32766,  766, 1142, 1143, 1144, 1138,\n         1137, 1136, 1145, 1139, 1140, 1141,  387,  388,  305,  271,\n           54,  390,  770,  771,  772,  773,  432,  846,  433,-32766,\n        -32766,-32766,  480,  481,  297,  827,  774,  775,  776,  777,\n          778,  779,  780,  781,  782,  783,  803,  575,  804,  805,\n          806,  807,  795,  796,  352,  353,  798,  799,  784,  785,\n          786,  788,  789,  790,  363,  830,  831,  832,  833,  834,\n          576, -194,  305,  849,  791,  792,  577,  578,    5,  815,\n          813,  814,  826,  810,  811, 1310,    3,  579,  580,  809,\n          581,  582,  583,  584, -581,  585,  586,  757,  756,  109,\n          110,  111,  812,  587,  588,  626,  140,  495,  134,  135,\n          136,  574,  137,  138, 1081,  763,  764,  765,  139,   41,\n        -32766,   29, 1043, 1038, 1037, 1036, 1042, 1039, 1040, 1041,\n        -32766,-32766,-32766, -628, 1397, -628, 1092, 1398,  243, -625,\n         1283, -625, -338,  757,  756, 1055,   87,-32766,-32766,-32766,\n          335,-32766,  954,-32766,-32766,-32766,-32766,-32766,-32766,-32766,\n         -195, -581, -581,  766,-32766,-32766,-32766,  847,-32766,  296,\n        -32766,-32766,-32766,-32766,-32766, 1368,  429,  271,   54,  390,\n          770,  771,  772,  773,   38,-32766,  433,-32766,-32766,-32766,\n        -32766, -581,  620,  827,  774,  775,  776,  777,  778,  779,\n          780,  781,  782,  783,  803,  575,  804,  805,  806,  807,\n          795,  796,  352,  353,  798,  799,  784,  785,  786,  788,\n          789,  790,  363,  830,  831,  832,  833,  834,  576, -194,\n         -579,  141,  791,  792,  577,  578,  848,  815,  813,  814,\n          826,  810,  811,  433,  302,  579,  580,  809,  581,  582,\n          583,  584,  145,  585,  586,  838,  335,  469,  470,  471,\n          812,  587,  588,  840,  140,  843,  134,  135,  136,  574,\n          137,  138, 1079,  763,  764,  765,  139,   41, 1142, 1143,\n         1144, 1138, 1137, 1136, 1145, 1139, 1140, 1141,  149,  242,\n         -275,-32766,-32766,-32766, 1092,   27, 1283, -579, -579, 1078,\n          256,  757,  756,-32767,-32767,-32767,-32767,  107,  108,  109,\n          110,  111,-32766, -579,-32766,-32766,-32766,  316,  500,  737,\n         1131,  766, 1285, 1284, 1286, -585, 1372, -579, -382,  293,\n         -382, 1117,  429, 1005, 1371,  271,   54,  390,  770,  771,\n          772,  773,  146,  842,  433,  844,  335,  757,  756,   52,\n          724,  827,  774,  775,  776,  777,  778,  779,  780,  781,\n          782,  783,  803,  575,  804,  805,  806,  807,  795,  796,\n          352,  353,  798,  799,  784,  785,  786,  788,  789,  790,\n          363,  830,  831,  832,  833,  834,  576, -577,  320, -578,\n          791,  792,  577,  578, -576,  815,  813,  814,  826,  810,\n          811, 1094,  332,  579,  580,  809,  581,  582,  583,  584,\n          -85,  585,  586,  958,  957, 1052,  306,  307,  812,  587,\n          588,  838,  140,  570,  134,  135,  136,  574,  137,  138,\n         1083,  763,  764,  765,  139,   41,  348,  112,  113,  114,\n         1055,  281,-32766,-32766,-32766, 1283,  131,-32766,-32766,-32766,\n          349, 1283, 1092,  115, -577, -577, -578, -578,-32766,  757,\n          756, -576, -576,  956,  289, 1006,  974,  975,-32766, 1055,\n         -577,  976, -578,-32766,-32766,-32766,  -85, -576,  132,  766,\n          970,  429, -584, 1055, -577,  377, -578,  429, 1322, -583,\n          381, -576,  397,  271,   54,  390,  770,  771,  772,  773,\n         1116,  399,  433,   10,  749,  451,  875,  296,  876,  827,\n          774,  775,  776,  777,  778,  779,  780,  781,  782,  783,\n          803,  575,  804,  805,  806,  807,  795,  796,  352,  353,\n          798,  799,  784,  785,  786,  788,  789,  790,  363,  830,\n          831,  832,  833,  834,  576,  -50,  669,   23,  791,  792,\n          577,  578,-32766,  815,  813,  814,  826,  810,  811,  452,\n         -575,  579,  580,  809,  581,  582,  583,  584,  847,  585,\n          586, 1387,   88,   89,   90,  144,  812,  587,  588,  453,\n          140,  787,  758,  759,  760,  761,  762,  153,  763,  764,\n          765,  800,  801,   40, 1283,   91,   92,   93,   94,   95,\n           96,   97,   98,   99,  100,  101,  102,  103,  104,  105,\n          106,  107,  108,  109,  110,  111,  112,  113,  114, 1052,\n          281,-32766, 1283,  603, 1283,  389,  388, -575, -575, -619,\n          429, -619,  115,  688,  689,  432,  766,   39,  253,  152,\n          415,  385,  386, -575, 1055,-32766,  297, 1290,  660,  661,\n          767,  768,  769,  770,  771,  772,  773, -575,  429,  836,\n          429,  391,  392,   53,  454,  853,  827,  774,  775,  776,\n          777,  778,  779,  780,  781,  782,  783,  803,  825,  804,\n          805,  806,  807,  795,  796,  797,  824,  798,  799,  784,\n          785,  786,  788,  789,  790,  829,  830,  831,  832,  833,\n          834,  835,  154,  156,  157,  791,  792,  793,  794, 1283,\n          815,  813,  814,  826,  810,  811,  158,  -78,  802,  808,\n          809,  816,  817,  819,  818,  293,  820,  821,  160,  847,\n          308,  309,-32766,  812,  823,  822,   55,   56,   57,   58,\n          526,   59,   60,  -58,   36, 1281,  380,   61,   62,  -57,\n           63,  -87,   31,  272,  129,  130,  142, 1055,  143,  148,\n          133,  161,  162,  163,  847,  164,  757,  756, 1314, 1054,\n          165, -309,  -84,  281, 1283,  702,  115,  698,  150,  -78,\n          847,  296,  -73,  -72,  -71,   64,   65,-32766, 1285, 1284,\n         1286,   66,  -70,   67,  250,  251,   68,   69,   70,   71,\n           72,   73,   74,   75, 1276,   31,  272,   48,  449, 1283,\n          429,  703,   80, 1316, 1317,  528,  -69,  847,  335, 1052,\n          -68, 1314,  542,  -67, 1302, 1303, 1304, 1305, 1307, 1299,\n         1300,  -66,  -65,  933,  534,  704,  705, 1306, 1301,  -46,\n          -18,  384,  383,   42, 1055,  429,  280,   78,  290,  738,\n          741,  347,  331,  335, 1285, 1284, 1286, 1276,  932,    2,\n          289,  151,  294,  538,  539,  295, -305,  285,  289,  286,\n          291,  292,  341,  838,  541,  542,  298, 1302, 1303, 1304,\n         1305, 1307, 1299, 1300,  304,  299,  713,   79,  950, 1149,\n         1306, 1301,  590, 1399, 1285, 1284, 1286,  305,   -4,  933,\n           76,-32766,   13,  670,  330,  331,  335,  527, -154, -154,\n         -154,  477,  715,  313,  971,  691,  310,  923,  675,  319,\n           46,   22,  529, -154,  530, -154,  531, -154,  532, -154,\n          311,  533, 1321, -541,  596,  505,   49,   50,  455,  382,\n          676,  692,   51,  535,-32766, 1323,  952,  624,  375, -531,\n          974,  975, -613,  305,  933,  536,  658,  846,    0,    0,\n          537, 1311,    0,  909,  970, -110, -110, -110, -278,    0,\n            0,    0,    0,  527,   44,    0,   11,   30,    0, 1290,\n            0,    0,  379,  923,    0,    0,   46,   22,  529,   45,\n          530,    0,  531,    0,  532,    0,  935,  533,    0,    0,\n          722, -154,   49,   50,  455,  382,  858,  445,   51,  535,\n          -16, 1338,  303, 1356,  375,  746,  974,  975,  747,  866,\n          914,  536, 1015,  992,  999,  933,  537,  989,  527,  540,\n          970, -110, -110, -110, 1000,  912,  987, 1120,  923, 1123,\n         1124,   46,   22,  529, 1121,  530, 1122,  531, 1128,  532,\n         1390,  663,  533,   21, -253, -253, -253,   49,   50,  455,\n          382,  847,  935,   51,  535, -612,  722,   -4, -611,  375,\n         -585,  974,  975, -584, -583, -582,  536, -525,    1,   32,\n           33,  537,   43,   47,  909,  970, -110, -110, -110,   77,\n           81,   82,   83,   84,   85,   86, -110, -110,  147,  527,\n         1115, -110,  155,  159,  248,  337,  364,  365,  366,  923,\n         -110,  367,   46,   22,  529,  368,  530,  935,  531,-32766,\n          532,  722, -253,  533,  369, -252, -252, -252,   49,   50,\n          455,  382,  370,  371,   51,  535,  372,  373,  374,  376,\n          375,  305,  974,  975,   80,  757,  756,  536,  446,  569,\n          335, -276,  537, -275, 1290,  909,  970, -110, -110, -110,\n           35,  116,  117,  118,  119,  120,  121,  122,  123,  124,\n          125,  126,  127,  128,   15,   16,   17,   18,   31,  273,\n           20,  413,  496,  497,  504,  507,  508,  509,  935,  510,\n          847,   37,  722, -252, 1314,  514,  515,  516,  524,  601,\n          933, -110,  708, 1191, 1193, 1231, -110, 1312, -110, 1082,\n         1080, 1061, 1271,  312, -575, 1057, -110, -110, -110, -110,\n         -110, -110, -110, -110, -110, -110, -110, -280, -102,   14,\n         1276,  727,   19,   24,  302,  412,  847,  615,  621,  649,\n          714, 1235, 1289, 1232,  933, 1369,  414,  541,  542,  329,\n         1302, 1303, 1304, 1305, 1307, 1299, 1300,  378,  723,  726,\n          730,  731,  733, 1306, 1301,  734,  735, 1315, -357,  736,\n          740, -110, -110,   78,  527,  728, -110,  933,  331,  335,\n          725, -575, -575,  418,  923, -110,  743,   46,   22,  529,\n          910,  530, 1394,  531,-32766,  532, 1396, -575,  533,  869,\n          868,  964, 1007,   49,   50,  455, 1395,  963,  729,   51,\n          535, -575, 1249,  961,  962,  375,  305,  965,  527,   80,\n         1264,  933,  335,  943,  953,  335,  941,  537,  923,  997,\n          998,   46,   22,  529,  647,  530, 1393,  531, 1350,  532,\n         1339, 1357,  533, 1366,    0,    0,    0,   49,   50,  455,\n            0,  527,  732,   51,  535,    0,    0,    0,  933,  375,\n            0,  923,    0,  935,   46,   22,  529,  722,  530,    0,\n          531,  537,  532,    0,    0,  533,    0,    0,    0,    0,\n           49,   50,  455,    0,    0,    0,   51,  535,    0,  739,\n            0,    0,  375,    0,    0,  527,    0,    0,    0,    0,\n            0,    0,  933,    0,  537,  923,    0,  935,   46,   22,\n          529,  722,  530,    0,  531,    0,  532,    0,    0,  533,\n            0,    0,    0,    0,   49,   50,  455,    0,    0,    0,\n           51,  535,  527,    0,    0,    0,  375,    0,    0,    0,\n          991,    0,  923,    0,  722,   46,   22,  529,  537,  530,\n            0,  531,    0,  532,    0,    0,  533,    0,   31,  273,\n            0,   49,   50,  455,    0,    0,    0,   51,  535,    0,\n          847,    0,    0,  375, 1314,    0,  527,    0,    0,    0,\n            0,    0,    0,    0,  935,  537,  923,    0,  722,   46,\n           22,  529,    0,  530,    0,  531,    0,  532,    0,    0,\n          533,    0,    0,    0,    0,   49,   50,  455,    0,    0,\n         1276,   51,  535,    0,    0,    0,    0,  375,    0,    0,\n            0,  935,    0,    0,    0,  722,    0,    0,  542,  537,\n         1302, 1303, 1304, 1305, 1307, 1299, 1300,    0,    0,    0,\n            0,    0,    0, 1306, 1301,    0,    0,    0,    0,    0,\n            0,    0,    0,   78,    0,    0,    0,    0,  331,  335,\n            0,    0,    0,    0,    0,  935,    0,    0,    0,  722\n    );\n\n    protected array $actionCheck = array(\n            3,    4,    5,    6,    7,    8,    1,   10,   11,   12,\n           13,   14,  107,  108,  109,   71,   10,   11,   12,    1,\n           81,   32,  117,    0,  107,    1,  109,    9,   31,    1,\n           10,   11,   12,    9,    9,   38,   39,   31,    9,   33,\n           34,   35,   36,   37,   38,   39,   40,   41,   42,   43,\n           44,   31,    9,   33,   34,   58,  117,  118,  119,  120,\n          121,  122,  123,  124,  125,  126,  107,  108,  163,   72,\n           73,   74,   75,   76,   77,   78,  117,  160,   81,   10,\n           11,   12,  138,  139,   31,   88,   89,   90,   91,   92,\n           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,\n          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,\n          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,\n          123,    9,  163,    1,  127,  128,  129,  130,    9,  132,\n          133,  134,  135,  136,  137,    1,    9,  140,  141,  142,\n          143,  144,  145,  146,   71,  148,  149,   38,   39,   51,\n           52,   53,  155,  156,  157,   52,  159,  168,    3,    4,\n            5,    6,    7,    8,  167,   10,   11,   12,   13,   14,\n          117,    9,  119,  120,  121,  122,  123,  124,  125,  126,\n           10,   11,   12,  165,   81,  167,   31,   84,   15,  165,\n           81,  167,  167,   38,   39,  142,  168,   10,   11,   12,\n          172,   31,    1,   33,   34,   35,   36,   37,   38,   39,\n          167,  138,  139,   58,   10,   11,   12,   83,   31,  166,\n           33,   34,   35,   36,   37,    1,  117,   72,   73,   74,\n           75,   76,   77,   78,    9,   31,   81,   33,   34,   35,\n           36,  168,    1,   88,   89,   90,   91,   92,   93,   94,\n           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,\n          105,  106,  107,  108,  109,  110,  111,  112,  113,  114,\n          115,  116,  117,  118,  119,  120,  121,  122,  123,  167,\n           71,    9,  127,  128,  129,  130,  164,  132,  133,  134,\n          135,  136,  137,   81,  167,  140,  141,  142,  143,  144,\n          145,  146,  168,  148,  149,   81,  172,  133,  134,  135,\n          155,  156,  157,   81,  159,   81,    3,    4,    5,    6,\n            7,    8,  167,   10,   11,   12,   13,   14,  117,  118,\n          119,  120,  121,  122,  123,  124,  125,  126,    9,   98,\n          167,   10,   11,   12,   31,  102,   81,  138,  139,    1,\n            9,   38,   39,   45,   46,   47,   48,   49,   50,   51,\n           52,   53,   31,  154,   33,   34,   35,    9,  103,  168,\n          127,   58,  160,  161,  162,  166,    1,  168,  107,   31,\n          109,  169,  117,   32,    9,   72,   73,   74,   75,   76,\n           77,   78,  168,  161,   81,  161,  172,   38,   39,   71,\n          168,   88,   89,   90,   91,   92,   93,   94,   95,   96,\n           97,   98,   99,  100,  101,  102,  103,  104,  105,  106,\n          107,  108,  109,  110,  111,  112,  113,  114,  115,  116,\n          117,  118,  119,  120,  121,  122,  123,   71,    9,   71,\n          127,  128,  129,  130,   71,  132,  133,  134,  135,  136,\n          137,   31,    9,  140,  141,  142,  143,  144,  145,  146,\n           32,  148,  149,   73,   74,  117,  138,  139,  155,  156,\n          157,   81,  159,   86,    3,    4,    5,    6,    7,    8,\n          167,   10,   11,   12,   13,   14,    9,   54,   55,   56,\n          142,   58,   10,   11,  117,   81,  168,   10,   11,   12,\n            9,   81,   31,   70,  138,  139,  138,  139,  117,   38,\n           39,  138,  139,  123,  166,  164,  118,  119,   31,  142,\n          154,  123,  154,   10,   11,   12,   98,  154,   15,   58,\n          132,  117,  166,  142,  168,    9,  168,  117,  151,  166,\n            9,  168,    9,   72,   73,   74,   75,   76,   77,   78,\n          164,  107,   81,  109,  168,    9,  107,  166,  109,   88,\n           89,   90,   91,   92,   93,   94,   95,   96,   97,   98,\n           99,  100,  101,  102,  103,  104,  105,  106,  107,  108,\n          109,  110,  111,  112,  113,  114,  115,  116,  117,  118,\n          119,  120,  121,  122,  123,   32,   76,   77,  127,  128,\n          129,  130,   10,  132,  133,  134,  135,  136,  137,    9,\n           71,  140,  141,  142,  143,  144,  145,  146,   83,  148,\n          149,   86,   10,   11,   12,   32,  155,  156,  157,    9,\n          159,    3,    4,    5,    6,    7,    8,   15,   10,   11,\n           12,   13,   14,   31,   81,   33,   34,   35,   36,   37,\n           38,   39,   40,   41,   42,   43,   44,   45,   46,   47,\n           48,   49,   50,   51,   52,   53,   54,   55,   56,  117,\n           58,  117,   81,   82,   81,  107,  108,  138,  139,  165,\n          117,  167,   70,   76,   77,  117,   58,  152,  153,  102,\n          103,  107,  108,  154,  142,  141,   31,    1,  112,  113,\n           72,   73,   74,   75,   76,   77,   78,  168,  117,   81,\n          117,  107,  108,   71,    9,    9,   88,   89,   90,   91,\n           92,   93,   94,   95,   96,   97,   98,   99,  100,  101,\n          102,  103,  104,  105,  106,  107,  108,  109,  110,  111,\n          112,  113,  114,  115,  116,  117,  118,  119,  120,  121,\n          122,  123,   15,   15,   15,  127,  128,  129,  130,   81,\n          132,  133,  134,  135,  136,  137,   15,   17,  140,  141,\n          142,  143,  144,  145,  146,   31,  148,  149,   15,   83,\n          138,  139,  117,  155,  156,  157,    2,    3,    4,    5,\n            6,    7,    8,   17,   15,  117,  154,   13,   14,   17,\n           16,   32,   71,   72,   17,   17,   17,  142,   17,   17,\n          168,   17,   17,   17,   83,   17,   38,   39,   87,  141,\n           17,   36,   32,   58,   81,   81,   70,   78,   71,   32,\n           83,  166,   32,   32,   32,   51,   52,  141,  160,  161,\n          162,   57,   32,   59,   60,   61,   62,   63,   64,   65,\n           66,   67,   68,   69,  123,   71,   72,   73,   74,   81,\n          117,  117,  166,   79,   80,   81,   32,   83,  172,  117,\n           32,   87,  141,   32,  143,  144,  145,  146,  147,  148,\n          149,   32,   32,    1,  100,  141,  142,  156,  157,   32,\n           32,  107,  108,   32,  142,  117,   32,  166,   32,   32,\n           32,  117,  171,  172,  160,  161,  162,  123,   32,  166,\n          166,   32,   38,  129,  130,   38,   36,   36,  166,   36,\n           36,   36,   36,   81,  140,  141,   38,  143,  144,  145,\n          146,  147,  148,  149,  150,   38,   81,  159,   39,   83,\n          156,  157,   90,   84,  160,  161,  162,  163,    0,    1,\n          166,   86,   98,   91,  170,  171,  172,   75,   76,   77,\n           78,   98,   93,  115,  132,   95,  136,   85,   97,  136,\n           88,   89,   90,   91,   92,   93,   94,   95,   96,   97,\n          137,   99,  151,  154,  158,   98,  104,  105,  106,  107,\n          101,  101,  110,  111,  141,  151,  159,  158,  116,  154,\n          118,  119,  166,  163,    1,  123,  114,  160,   -1,   -1,\n          128,  165,   -1,  131,  132,  133,  134,  135,  167,   -1,\n           -1,   -1,   -1,   75,  164,   -1,  154,  154,   -1,    1,\n           -1,   -1,  154,   85,   -1,   -1,   88,   89,   90,  164,\n           92,   -1,   94,   -1,   96,   -1,  164,   99,   -1,   -1,\n          168,  169,  104,  105,  106,  107,  165,  109,  110,  111,\n           32,  165,  114,  165,  116,  164,  118,  119,  164,  164,\n          164,  123,  164,  164,  164,    1,  128,  164,   75,  131,\n          132,  133,  134,  135,  164,  164,  164,  164,   85,  164,\n          164,   88,   89,   90,  164,   92,  164,   94,  164,   96,\n          165,  165,   99,  155,  101,  102,  103,  104,  105,  106,\n          107,   83,  164,  110,  111,  166,  168,  169,  166,  116,\n          166,  118,  119,  166,  166,  166,  123,  166,  166,  166,\n          166,  128,  166,  166,  131,  132,  133,  134,  135,  166,\n          166,  166,  166,  166,  166,  166,  118,  119,  166,   75,\n            1,  123,  166,  166,  166,  166,  166,  166,  166,   85,\n          132,  166,   88,   89,   90,  166,   92,  164,   94,  141,\n           96,  168,  169,   99,  166,  101,  102,  103,  104,  105,\n          106,  107,  166,  166,  110,  111,  166,  166,  166,  166,\n          116,  163,  118,  119,  166,   38,   39,  123,  166,  166,\n          172,  167,  128,  167,    1,  131,  132,  133,  134,  135,\n           17,   18,   19,   20,   21,   22,   23,   24,   25,   26,\n           27,   28,   29,   30,  167,  167,  167,  167,   71,   72,\n          167,  167,  167,  167,  167,  167,  167,  167,  164,  167,\n           83,  168,  168,  169,   87,  167,  167,  167,  167,  167,\n            1,  102,  167,   60,   61,  167,  107,  167,  109,  167,\n          167,  167,  167,  114,   71,  167,  117,  118,  119,  120,\n          121,  122,  123,  124,  125,  126,  127,  167,  167,  167,\n          123,   32,  167,  167,  167,  167,   83,  167,  167,  167,\n          167,  167,  167,  167,    1,  167,  169,  140,  141,  168,\n          143,  144,  145,  146,  147,  148,  149,  168,  168,  168,\n          168,  168,  168,  156,  157,  168,  168,  171,  169,  168,\n          168,  118,  119,  166,   75,   32,  123,    1,  171,  172,\n          168,  138,  139,  169,   85,  132,  169,   88,   89,   90,\n          169,   92,  169,   94,  141,   96,  169,  154,   99,  169,\n          169,  169,  169,  104,  105,  106,  169,  169,   32,  110,\n          111,  168,  170,  169,  169,  116,  163,  169,   75,  166,\n          169,    1,  172,  169,  169,  172,  169,  128,   85,  169,\n          169,   88,   89,   90,  169,   92,  169,   94,  169,   96,\n          169,  169,   99,  169,   -1,   -1,   -1,  104,  105,  106,\n           -1,   75,   32,  110,  111,   -1,   -1,   -1,    1,  116,\n           -1,   85,   -1,  164,   88,   89,   90,  168,   92,   -1,\n           94,  128,   96,   -1,   -1,   99,   -1,   -1,   -1,   -1,\n          104,  105,  106,   -1,   -1,   -1,  110,  111,   -1,   32,\n           -1,   -1,  116,   -1,   -1,   75,   -1,   -1,   -1,   -1,\n           -1,   -1,    1,   -1,  128,   85,   -1,  164,   88,   89,\n           90,  168,   92,   -1,   94,   -1,   96,   -1,   -1,   99,\n           -1,   -1,   -1,   -1,  104,  105,  106,   -1,   -1,   -1,\n          110,  111,   75,   -1,   -1,   -1,  116,   -1,   -1,   -1,\n          164,   -1,   85,   -1,  168,   88,   89,   90,  128,   92,\n           -1,   94,   -1,   96,   -1,   -1,   99,   -1,   71,   72,\n           -1,  104,  105,  106,   -1,   -1,   -1,  110,  111,   -1,\n           83,   -1,   -1,  116,   87,   -1,   75,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,  164,  128,   85,   -1,  168,   88,\n           89,   90,   -1,   92,   -1,   94,   -1,   96,   -1,   -1,\n           99,   -1,   -1,   -1,   -1,  104,  105,  106,   -1,   -1,\n          123,  110,  111,   -1,   -1,   -1,   -1,  116,   -1,   -1,\n           -1,  164,   -1,   -1,   -1,  168,   -1,   -1,  141,  128,\n          143,  144,  145,  146,  147,  148,  149,   -1,   -1,   -1,\n           -1,   -1,   -1,  156,  157,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,  166,   -1,   -1,   -1,   -1,  171,  172,\n           -1,   -1,   -1,   -1,   -1,  164,   -1,   -1,   -1,  168\n    );\n\n    protected array $actionBase = array(\n            0,  155,   -3,  313,  471,  471,  882,  948, 1003, 1074,\n          744,  134,  212,  -61, 1293, 1370, 1370, 1407, 1370, 1249,\n         1326,  232, 1451, 1451, 1451,  932,  855,  628,  628,  855,\n          628,  778,  778,  778,  778,  109,  109,  265,  265,  591,\n          593,  563,  420,  414,  414,  414,  414,  414,  743,  414,\n          414,  414,  414,  414,  743,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  414,  414,  414,  414,\n          414,  414,  414,  414,  414,  414,  122,  351,  127,  241,\n          779, 1117, 1124, 1120, 1125, 1115, 1112, 1118, 1121, 1126,\n         1217, 1219,  879, 1221, 1222, 1215, 1224, 1122,  936, 1116,\n         1123,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  592,\n          513,  482,   69,   69,   69,   69,   69,   69,   69,   69,\n           69,   69,   69,   69,   69,   69,   69,   69,   69,   69,\n           69,   69, 1157, 1157,  487,  487,  487,   20, 1437,  731,\n         1437, 1437, 1437, 1437, 1437, 1437, 1437, 1437,  331,  204,\n         1193,  187,  170,  170,    6,    6,    6,    6,    6, 1149,\n           53, 1028, 1203, 1203,  308,  308,  308,  308,  243,  271,\n          348,  696,  -95,  665,  -41,  752,  752,   98,   98,  552,\n          552,  391,  391,  552,  552,  552,  377,  377,  377,  377,\n          209,  366,  373,  -83,  387,  853,  224,  224,  224,  224,\n          853,  853,  853,  853,  844, 1146,  853,  990, 1008,  853,\n          853,  368,  539,  539,  642,  433,  433,  433,  539,  449,\n          535,  535,  449,  398,  535,   28,  103,  554,  832,  568,\n          514,  554,   73,  328,   24,   18,  847,  584,  847, 1111,\n          865,  865,  857,  800,  934, 1162, 1128,  889, 1210,  890,\n         1211,  174,  -56,  797, 1110, 1110, 1110, 1110, 1110, 1110,\n         1110, 1110, 1110, 1110, 1110, 1200,  359, 1111,  234, 1200,\n         1200, 1200,  359,  359,  359,  359,  359,  359,  359,  359,\n          858,  359,  359,  586,  234,  520,  607,  234,  886,  359,\n          845,  122,  122,  122,  122,  122,  122,  122,  122,  122,\n          122,  122,  -11,  122,  122,  351,  201,  201,  122,  386,\n            5,  201,  201,  201,  201,  122,  122,  122,  122,  584,\n          765,  826,  604,  428,  839,  112,  765,  765,  765,   25,\n          173,   43,  785,  880,  444,  842,  842,  842,  856,  962,\n          962,  842,  747,  842,  856,  842,  842,  962,  962,  840,\n          962,  272,  546,  477,  531,  600,  962,  358,  842,  842,\n          842,  842,  833,  962,   29,  119,  620,  842,  341,  329,\n          842,  842,  833,  830,  866,  843,  962,  962,  962,  833,\n          526,  843,  843,  843,  901,  904,  892,  864,  443,  429,\n          706,  225,  899,  864,  864,  842,  533,  892,  864,  892,\n          864,  837,  864,  864,  864,  892,  864,  747,  491,  864,\n          794,  795,  705,  162,  864,   23,  973,  974,  769,  975,\n          966,  976, 1032,  977,  978, 1140,  961,  988,  967,  979,\n         1033,  964,  963,  876,  787,  788,  872,  829,  959,  756,\n          756,  756,  954,  957,  756,  756,  756,  756,  756,  756,\n          756,  756,  787,  846,  878,  852,  991,  789,  791, 1082,\n          831, 1171, 1192,  990,  973,  978,  790,  967,  979,  964,\n          963,  850,  849,  838,  841,  834,  810,  801,  802,  861,\n          982,  860,  792, 1063,  992, 1167, 1131,  995,  999, 1064,\n         1088,  905, 1090, 1173,  757, 1177, 1180,  891, 1016, 1141,\n          756,  952,  836,  896, 1008,  958,  787,  898, 1092, 1093,\n         1057, 1073, 1065, 1066, 1139,  863,  859,  935, 1181, 1017,\n         1020, 1021, 1142, 1143,  875, 1058,  851, 1067,  887, 1127,\n         1068, 1069, 1070, 1072, 1144, 1182, 1147,  949, 1148,  906,\n          862, 1034,  871, 1183,  622,  884,  885,  897, 1023,  737,\n          989, 1151, 1164, 1187, 1078, 1079, 1080, 1188, 1194,  986,\n          908, 1059,  870, 1060, 1036,  909,  910,  738,  888, 1094,\n          881,  883,  877,  739,  751, 1195, 1198, 1201,  987,  867,\n          749,  913,  920, 1095,  874, 1098, 1204,  763,  921, 1205,\n         1085,  796,  798,  750,  782,  776,  803,  869, 1152,  873,\n          848,  854, 1022,  798,  868,  922, 1207,  923,  925,  926,\n         1081,  930,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  628,  628,  628,  628,  784,  784,  784,  784,  784,\n          784,  784,  628,  784,  784,  784,  628,  628,    0,    0,\n          628,    0,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  784,  784,  784,\n          784,  784,  784,  784,  784,  784,  784,  612,  612,  612,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,  612,  612,  612,  612,  612,  612,  612,  612,\n          612,  612,  612,  678,  678,  612,  612,  612,  612,  678,\n          678,  678,  678,  678,  678,  678,  678,  678,  678,  612,\n          612,    0,  612,  612,  612,  612,  612,  612,  612,  612,\n          840,  678,  678,  678,  678,  433,  433,  433,  433,  211,\n          211,  678,  678,  398,  678,  398,  678,  678,  433,  433,\n          678,  678,  678,  678,  678,  678,  678,  678,  678,  678,\n          678,    0,    0,    0,  234,  535,  678,  747,  747,  747,\n          747,  678,  678,  678,  678,  535,  535,  678,  390,  390,\n          678,  678,    0,    0,    0,    0,    0,    0,    0,    0,\n          234,    0,    0,  234,    0,    0,  747,  747,  678,  398,\n          840,  375,  678,    0,    0,    0,    0,  234,  747,  234,\n          359,  535,  535,  359,  359,  201,  122,  375,  587,  587,\n          587,  587,    0,    0,  584,  840,  840,  840,  840,  840,\n          840,  840,  840,  840,  840,  840,  747,    0,  840,    0,\n          747,  747,  747,    0,    0,    0,    0,    0,    0,    0,\n            0,  962,    0,    0,    0,    0,    0,    0,    0,  747,\n            0,  962,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,  747,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,  756,  863,    0,    0,  863,    0,  756,  756,  756,\n            0,    0,    0,  888,  874\n    );\n\n    protected array $actionDefault = array(\n            3,32767,32767,32767,  102,  102,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,  100,\n        32767,  631,  631,  631,  631,32767,32767,  257,  102,32767,\n        32767,  500,32767,  415,  415,  415,32767,32767,32767,  573,\n          573,  573,  573,  573,   17,32767,32767,32767,32767,32767,\n        32767,32767,  500,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,   36,    7,    8,   10,   11,   49,\n          340,  100,32767,32767,32767,32767,32767,32767,32767,  102,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n          624,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  403,  494,  504,  482,  483,  485,  486,  414,  574,\n          630,  344,  627,  339,  413,  146,  354,  342,  245,  261,\n          505,  262,  506,  509,  510,  218,  400,  150,  151,  446,\n          501,  448,  499,  503,  447,  420,  427,  428,  429,  430,\n          431,  432,  433,  434,  435,  436,  437,  438,  439,  418,\n          419,  502,32767,32767,  479,  478,  477,  444,32767,32767,\n        32767,32767,32767,32767,32767,32767,  102,32767,  445,  449,\n          417,  452,  450,  451,  468,  469,  466,  467,  470,32767,\n          323,32767,32767,32767,  471,  472,  473,  474,  381,  379,\n        32767,32767,  111,  323,  111,32767,32767,  459,  460,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n          517,  567,  476,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,  102,32767,32767,32767,\n          100,  569,  441,  443,  537,  454,  455,  453,  421,32767,\n          542,32767,  102,32767,  544,32767,32767,32767,32767,32767,\n        32767,32767,  568,32767,  575,  575,32767,  530,  100,  196,\n        32767,  543,  196,  196,32767,32767,32767,32767,32767,32767,\n        32767,32767,  638,  530,  110,  110,  110,  110,  110,  110,\n          110,  110,  110,  110,  110,32767,  196,  110,32767,32767,\n        32767,  100,  196,  196,  196,  196,  196,  196,  196,  196,\n          545,  196,  196,  191,32767,  271,  273,  102,  592,  196,\n          547,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,  530,\n          464,  139,32767,  532,  139,  575,  456,  457,  458,  575,\n          575,  575,  319,  296,32767,32767,32767,32767,32767,  545,\n          545,  100,  100,  100,  100,32767,32767,32767,32767,  111,\n          516,   99,   99,   99,   99,   99,  103,  101,32767,32767,\n        32767,32767,  226,32767,  101,  101,   99,32767,  101,  101,\n        32767,32767,  226,  228,  215,  230,32767,  596,  597,  226,\n          101,  230,  230,  230,  250,  250,  519,  325,  101,   99,\n          101,  101,  198,  325,  325,32767,  101,  519,  325,  519,\n          325,  200,  325,  325,  325,  519,  325,32767,  101,  325,\n          217,  403,   99,   99,  325,32767,32767,32767,  532,32767,\n        32767,32767,32767,32767,32767,32767,  225,32767,32767,32767,\n        32767,32767,32767,32767,32767,  562,32767,  580,  594,  462,\n          463,  465,  579,  577,  487,  488,  489,  490,  491,  492,\n          493,  496,  626,32767,  536,32767,32767,32767,  353,32767,\n          636,32767,32767,32767,    9,   74,  525,   42,   43,   51,\n           57,  551,  552,  553,  554,  548,  549,  555,  550,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,  637,32767,  575,32767,32767,32767,32767,\n          461,  557,  602,32767,32767,  576,  629,32767,32767,32767,\n        32767,32767,32767,32767,32767,  139,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,  562,32767,  137,32767,\n        32767,32767,32767,32767,32767,32767,32767,  558,32767,32767,\n        32767,  575,32767,32767,32767,32767,  321,  318,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,  575,32767,32767,32767,32767,32767,\n          298,32767,  315,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  399,  532,  301,  303,  304,32767,32767,32767,32767,\n          375,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,  153,  153,    3,    3,  356,  153,  153,  153,\n          356,  356,  153,  356,  356,  356,  153,  153,  153,  153,\n          153,  153,  283,  186,  265,  268,  250,  250,  153,  367,\n          153\n    );\n\n    protected array $goto = array(\n          201,  168,  201,  201,  201, 1053,  926,  709,  927,  667,\n          668,  595,  685,  686,  687,  745,  650,  652, 1085,  358,\n          672,  634,  671,  718,  696,  699, 1025,  707,  716, 1021,\n          170,  170,  170,  170,  225,  202,  198,  198,  180,  182,\n          220,  207,  198,  198,  198,  198,  198, 1177,  199,  199,\n          199,  199,  199, 1177,  192,  193,  194,  195,  196,  197,\n          222,  220,  223,  549,  550,  430,  551,  554,  555,  556,\n          557,  558,  559,  560,  561,  171,  172,  173,  200,  174,\n          175,  176,  169,  177,  178,  179,  181,  219,  221,  224,\n          244,  247,  258,  259,  261,  262,  263,  264,  265,  266,\n          267,  268,  274,  275,  276,  277,  287,  288,  325,  326,\n          327,  436,  437,  438,  610,  226,  227,  228,  229,  230,\n          231,  232,  233,  234,  235,  236,  237,  238,  239,  240,\n          183,  241,  184,  193,  194,  195,  196,  197,  222,  203,\n          204,  205,  206,  245,  185,  186,  187,  208,  204,  188,\n          246,  167,  209,  210,  189,  211,  212,  213,  190,  214,\n          215,  191,  216,  217,  218,  284,  282,  284,  284,  867,\n         1084, 1086, 1088,  612,  254,  254,  254,  254,  254,  440,\n          674,  611, 1127, 1134, 1135,  435,  328,  322,  323,  344,\n          605,  439,  345,  441,  651,  721,  491,  520,  712,  434,\n         1125,  625,  845,  493,  252,  252,  252,  252,  249,  255,\n          361,  361,  361,  361,  864,  922,  917,  918,  931,  873,\n          919,  870,  920,  921,  871,  874,  362,  925,  878,  982,\n          419,  717,  877,  442, 1059, 1058,  362,  362,  865, 1114,\n         1109, 1110, 1111, 1258,  959,  845,  442,  845, 1259, 1262,\n          960, 1263,  362,  362, 1060, 1060,  362,  839, 1400,  678,\n         1071, 1067, 1068,  706,  428, 1053, 1282, 1282, 1282,  568,\n          359,  360,  362,  362,  841, 1053, 1282,  990, 1053,  706,\n         1053, 1053,  706,  350, 1053, 1053, 1053, 1053, 1053, 1053,\n         1053, 1053, 1053, 1053, 1053,  906,  863,  906,  906,  899,\n         1282,  403,  406,  613,  617, 1282, 1282, 1282, 1282,  351,\n          350, 1282, 1062, 1063, 1282, 1282, 1365, 1365, 1365, 1365,\n         1344,  573,  566,  473,  602, 1056, 1056,  955,  955,  694,\n          967, 1226,  939, 1048, 1064, 1065,  940,  564,  564,  564,\n         1014,  356,  521,  986,  860,  744,  860,  564,  565, 1023,\n         1018,  317,  566,  573,  597,  598,  318,  608,  614, 1011,\n          630,  631,  479,  479,    8,  512,    9,  513,   28,  334,\n          315,  466,  479,  519,  568, 1373,  984,  984,  984,  984,\n         1360, 1361,  466,  636,  636,  978,  985,  606,  628, 1313,\n         1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1313, 1332,\n         1332,  860,  468,  401,  468, 1332, 1332, 1332, 1332, 1332,\n         1332, 1332, 1332, 1332, 1332,  257,  257,  623,  637,  640,\n          641,  642,  643,  664,  665,  666,  720,  600,  459,  673,\n          459,  459,  459, 1355, 1355, 1355,  552,  552, 1173, 1275,\n         1077,  448,  552, 1355,  552,  552,  552,  552,  552,  552,\n          552,  552,  695,  450,  857,  567,  592,  567,  488, 1358,\n         1359,  567,  679,  592,  346,  404,  472,  629, 1367, 1367,\n         1367, 1367,  886,  278,  973,  333,  333,  333,  482,  609,\n          483,  484,  883,  562,  562,  562,  562,  891,  616,  410,\n         1391, 1392, 1329, 1329, 1273,  881, 1033, 1351, 1329, 1329,\n         1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329,  644,  646,\n          648,  893, 1098,  748,  880,  889, 1277,  411,  489, 1102,\n          895,  860,    0,  459,  459,  459,  459,  459,  459,  459,\n          459,  459,  459,  459,  995, 1044,  459, 1100,  553,  553,\n         1148, 1353, 1353, 1100,  553,  553,  553,  553,  553,  553,\n          553,  553,  553,  553,  618,  619,  416,  417,  944, 1163,\n            0,  683,    0,  684,    0,  421,  422,  423,    0,  697,\n         1030,    0,  424, 1278, 1279,    0, 1265,  354,  885,    0,\n          677, 1009,  855,    0,    0,    0,  879, 1383, 1383, 1265,\n            0,  894,  882, 1097, 1101,    0,    0,    0, 1272,    0,\n            0,    0, 1280, 1341, 1342,  993,    0, 1383,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0, 1386, 1386,    0,    0,    0,  983,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0, 1146,  898,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0, 1028, 1028\n    );\n\n    protected array $gotoCheck = array(\n           42,   42,   42,   42,   42,   73,   65,   73,   65,   86,\n           86,   48,   86,   86,   86,   48,   48,   48,  130,   97,\n           48,   56,   56,    9,   48,   48,   48,   48,   48,   48,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   23,   23,   23,   23,   15,\n          129,  129,  129,  133,    5,    5,    5,    5,    5,   66,\n           66,    8,    8,  147,  147,   66,   66,   66,   66,   66,\n           66,   66,   66,   66,   66,    8,   84,    8,    8,   13,\n            8,   13,   12,   84,    5,    5,    5,    5,    5,    5,\n           24,   24,   24,   24,   26,   15,   15,   15,   15,   15,\n           15,   15,   15,   15,   15,   15,   14,   15,   15,   93,\n           93,   93,   15,  118,  119,  119,   14,   14,   27,   15,\n           15,   15,   15,   79,   79,   12,  118,   12,   79,   79,\n           79,   79,   14,   14,  118,  118,   14,    6,   14,  118,\n          118,  118,  118,    7,   43,   73,   73,   73,   73,   14,\n           97,   97,   14,   14,    7,   73,   73,   49,   73,    7,\n           73,   73,    7,  176,   73,   73,   73,   73,   73,   73,\n           73,   73,   73,   73,   73,   25,   25,   25,   25,   45,\n           73,   59,   59,   59,   59,   73,   73,   73,   73,  176,\n          176,   73,  120,  120,   73,   73,    9,    9,    9,    9,\n           14,   76,   76,  158,  180,   89,   89,    9,    9,   89,\n           89,  158,   73,   89,   89,   89,   73,   19,   19,   19,\n           50,  187,   14,   50,   22,   50,   22,   19,   50,   50,\n           50,   76,   76,   76,   76,   76,   76,   76,   76,  103,\n           76,   76,  156,  156,   46,  162,   46,  162,   76,  177,\n          177,   19,  156,  162,   14,  189,   19,   19,   19,   19,\n          186,  186,   19,  108,  108,   19,   19,    2,    2,  108,\n          108,  108,  108,  108,  108,  108,  108,  108,  108,  178,\n          178,   22,   83,   62,   83,  178,  178,  178,  178,  178,\n          178,  178,  178,  178,  178,    5,    5,   81,   81,   81,\n           81,   81,   81,   81,   81,   81,   81,  104,   23,   64,\n           23,   23,   23,  133,  133,  133,  164,  164,  157,   14,\n          115,  113,  164,  133,  164,  164,  164,  164,  164,  164,\n          164,  164,  117,   83,   18,    9,    9,    9,  184,  184,\n          184,    9,  121,    9,   29,    9,    9,   80,  133,  133,\n          133,  133,   39,   24,   92,   24,   24,   24,    9,    9,\n            9,    9,   37,  107,  107,  107,  107,    9,  107,   28,\n            9,    9,  179,  179,  168,   35,  110,  133,  179,  179,\n          179,  179,  179,  179,  179,  179,  179,  179,   85,   85,\n           85,   35,  132,   99,   35,    9,   20,   31,  159,  135,\n           41,   22,   -1,   23,   23,   23,   23,   23,   23,   23,\n           23,   23,   23,   23,   96,  114,   23,  133,  181,  181,\n          150,  133,  133,  133,  181,  181,  181,  181,  181,  181,\n          181,  181,  181,  181,   17,   17,   82,   82,   17,   17,\n           -1,   82,   -1,   82,   -1,   82,   82,   82,   -1,   82,\n           17,   -1,   82,   20,   20,   -1,   20,   82,   17,   -1,\n           17,   17,   20,   -1,   -1,   -1,   17,  190,  190,   20,\n           -1,   16,   16,   16,   16,   -1,   -1,   -1,   17,   -1,\n           -1,   -1,   20,   20,   20,   16,   -1,  190,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,  190,  190,   -1,   -1,   -1,   16,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   16,   16,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,  107,  107\n    );\n\n    protected array $gotoBase = array(\n            0,    0, -337,    0,    0,  173,  244,  253,  170,   10,\n            0,    0, -101, -147,  -78, -186,  129,   80,  138,   66,\n          116,    0,   62,  159,  204,  289,  207,  231,  143,  161,\n            0,   70,    0,    0,    0,  117,    0,  134,    0,  140,\n            0,   69,   -1,  238,    0,  270, -384,    0, -712,  257,\n          326,    0,    0,    0,    0,    0,  -23,    0,    0,  251,\n            0,    0,  357,    0,  186,  -10,  -63,    0,    0,    0,\n            0,    0,    0,   -5,    0,    0,  -31,    0,    0, -173,\n          149,   52,   53,  120, -286,   17, -721,    0,    0,   40,\n            0,    0,  136,  -82,    0,    0,   81, -476,    0,   98,\n            0,    0,    0,  321,  380,    0,    0,  452,  141,    0,\n          119,    0,    0,  158,   14,  160,    0,  163,  -37,  -51,\n           21,  166,    0,    0,    0,    0,    0,    0,    0,  167,\n           16,    0,  131,  162,    0,   67,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,  -95,    0,    0,\n           86,    0,    0,    0,    0,    0,  325,  189,   50,   68,\n            0,    0, -142,    0,  194,    0,    0,    0,  118,    0,\n            0,    0,    0,    0,    0,    0,  -21,   39,  157,  250,\n          292,  296,    0,    0,  151,    0,    1,  308,    0,  341,\n          273,    0,    0\n    );\n\n    protected array $gotoDefault = array(\n        -32768,  525,  752,    7,  753,  948,  828,  837,  589,  543,\n          719,  355,  638,  431, 1349,  924, 1162,  607,  856, 1291,\n         1297,  467,  859,  339,  742,  936,  907,  908,  407,  394,\n          872,  405,  662,  639,  506,  892,  463,  884,  498,  887,\n          462,  896,  166,  427,  523,  900,    6,  903,  571,  934,\n          988,  395,  911,  396,  690,  913,  591,  915,  916,  402,\n          408,  409, 1167,  599,  635,  928,  260,  593,  929,  393,\n          930,  938,  398,  400,  700,  478,  517,  511,  420, 1129,\n          594,  622,  659,  456,  485,  633,  645,  632,  492,  443,\n          425,  338,  972,  980,  499,  476,  994,  357, 1002,  750,\n         1175,  653,  501, 1010,  654, 1017, 1020,  544,  545,  490,\n         1032,  270, 1035,  502, 1045,   26,  680, 1050, 1051,  681,\n          655, 1073,  656,  682,  657, 1075,  475, 1176,  474, 1087,\n         1096,  464, 1099, 1337,  465, 1103,  269, 1106,  283,  426,\n          444, 1112, 1113,   12, 1119,  710,  711,   25,  279,  522,\n         1147,  701,-32768,-32768,-32768,-32768,  461, 1174,  460, 1246,\n         1248,  572,  503, 1266,  300, 1269,  693,  518, 1274,  457,\n         1340,  458,  546,  486,  324,  547, 1384,  314,  342,  321,\n          563,  301,  343,  548,  487, 1346, 1354,  340,   34, 1374,\n         1385,  604,  627\n    );\n\n    protected array $ruleToNonTerminal = array(\n            0,    1,    3,    3,    2,    5,    5,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    7,    7,    7,\n            7,    7,    7,    7,    7,    8,    8,    9,   10,   11,\n           11,   11,   12,   12,   13,   13,   14,   15,   15,   16,\n           16,   17,   17,   18,   18,   21,   21,   22,   23,   23,\n           24,   24,    4,    4,    4,    4,    4,    4,    4,    4,\n            4,    4,    4,    4,   29,   29,   30,   30,   32,   34,\n           34,   28,   36,   36,   33,   38,   38,   35,   35,   37,\n           37,   39,   39,   31,   40,   40,   41,   43,   44,   44,\n           45,   45,   46,   46,   48,   47,   47,   47,   47,   49,\n           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,\n           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,\n           49,   49,   49,   25,   25,   50,   69,   69,   72,   72,\n           71,   70,   70,   63,   75,   75,   76,   76,   77,   77,\n           78,   78,   79,   79,   80,   80,   80,   80,   26,   26,\n           27,   27,   27,   27,   27,   88,   88,   90,   90,   83,\n           83,   91,   91,   92,   92,   92,   84,   84,   87,   87,\n           85,   85,   93,   94,   94,   57,   57,   65,   65,   68,\n           68,   68,   67,   95,   95,   96,   58,   58,   58,   58,\n           97,   97,   98,   98,   99,   99,  100,  101,  101,  102,\n          102,  103,  103,   55,   55,   51,   51,  105,   53,   53,\n          106,   52,   52,   54,   54,   64,   64,   64,   64,   81,\n           81,  109,  109,  111,  111,  112,  112,  112,  112,  112,\n          112,  112,  112,  110,  110,  110,  115,  115,  115,  115,\n           89,   89,  118,  118,  118,  119,  119,  116,  116,  120,\n          120,  122,  122,  123,  123,  117,  124,  124,  121,  125,\n          125,  125,  125,  113,  113,   82,   82,   82,   20,   20,\n          127,  127,  127,  128,  128,  128,  126,  126,  130,  130,\n          130,  130,  130,  130,  129,  129,   60,  131,  131,  132,\n           61,  134,  134,  135,  135,  136,  136,   86,  137,  137,\n          137,  137,  137,  137,  137,  142,  142,  143,  143,  144,\n          144,  144,  144,  144,  145,  146,  146,  141,  141,  138,\n          138,  140,  140,  148,  148,  147,  147,  147,  147,  147,\n          147,  147,  147,  147,  147,  139,  149,  149,  151,  150,\n          150,  152,  152,  114,  153,  153,  155,  155,  155,  154,\n          154,   62,  104,  156,  156,   56,   56,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,  163,  164,  164,  165,  157,  157,  162,\n          162,  166,  167,  167,  168,  169,  170,  170,  170,  170,\n           19,   19,   73,   73,   73,   73,  158,  158,  158,  158,\n          172,  172,  161,  161,  161,  159,  159,  178,  178,  178,\n          178,  178,  178,  178,  178,  178,  178,  179,  179,  179,\n          108,  181,  181,  181,  181,  160,  160,  160,  160,  160,\n          160,  160,  160,   59,   59,  175,  175,  175,  175,  175,\n          182,  182,  171,  171,  171,  171,  183,  183,  183,  183,\n          183,  183,   74,   74,   66,   66,   66,   66,  133,  133,\n          133,  133,  186,  185,  174,  174,  174,  174,  174,  174,\n          174,  173,  173,  173,  184,  184,  184,  184,  107,  180,\n          188,  188,  187,  187,  189,  189,  189,  189,  189,  189,\n          189,  189,  177,  177,  177,  177,  176,  191,  190,  190,\n          190,  190,  190,  190,  190,  190,  192,  192,  192,  192\n    );\n\n    protected array $ruleToLength = array(\n            1,    1,    2,    0,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    0,\n            1,    0,    1,    1,    2,    1,    3,    4,    1,    2,\n            0,    1,    1,    1,    1,    4,    3,    5,    4,    3,\n            4,    1,    3,    4,    1,    1,    8,    7,    2,    3,\n            1,    2,    3,    1,    2,    3,    1,    1,    3,    1,\n            3,    1,    2,    2,    3,    1,    3,    2,    3,    1,\n            3,    3,    2,    0,    1,    1,    1,    1,    1,    3,\n            7,   10,    5,    7,    9,    5,    3,    3,    3,    3,\n            3,    3,    1,    2,    5,    7,    9,    6,    5,    6,\n            3,    2,    1,    1,    1,    1,    0,    2,    1,    3,\n            8,    0,    4,    2,    1,    3,    0,    1,    0,    1,\n            0,    1,    3,    1,    1,    1,    1,    1,    8,    9,\n            7,    8,    7,    6,    8,    0,    2,    0,    2,    1,\n            2,    1,    2,    1,    1,    1,    0,    2,    0,    2,\n            0,    2,    2,    1,    3,    1,    4,    1,    4,    1,\n            1,    4,    2,    1,    3,    3,    3,    4,    4,    5,\n            0,    2,    4,    3,    1,    1,    7,    0,    2,    1,\n            3,    3,    4,    1,    4,    0,    2,    5,    0,    2,\n            6,    0,    2,    0,    3,    1,    2,    1,    1,    2,\n            0,    1,    3,    0,    2,    1,    1,    1,    1,    1,\n            1,    1,    1,    7,    9,    6,    1,    2,    1,    1,\n            1,    1,    1,    1,    1,    1,    3,    3,    3,    1,\n            3,    3,    3,    3,    3,    1,    3,    3,    1,    1,\n            2,    1,    1,    0,    1,    0,    2,    2,    2,    4,\n            2,    4,    4,    3,    1,    3,    1,    3,    2,    2,\n            1,    1,    3,    3,    1,    1,    2,    3,    1,    1,\n            2,    3,    1,    1,    3,    2,    0,    1,    5,    5,\n            6,   10,    3,    5,    1,    1,    3,    0,    2,    4,\n            5,    4,    4,    4,    3,    1,    1,    1,    1,    1,\n            1,    0,    1,    1,    2,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    2,    1,    3,    1,    1,\n            3,    0,    2,    0,    5,    8,    1,    3,    3,    0,\n            2,    2,    2,    3,    1,    0,    1,    1,    3,    3,\n            3,    4,    4,    1,    1,    2,    2,    3,    3,    3,\n            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,\n            2,    2,    2,    2,    3,    3,    3,    3,    3,    3,\n            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,\n            3,    3,    2,    2,    2,    2,    3,    3,    3,    3,\n            3,    3,    3,    3,    3,    3,    3,    5,    4,    3,\n            4,    4,    2,    2,    4,    2,    2,    2,    2,    2,\n            2,    2,    2,    2,    2,    2,    2,    1,    3,    2,\n            1,    2,    4,    2,    2,    8,    9,    8,    9,    9,\n           10,    9,   10,    8,    3,    2,    2,    1,    1,    0,\n            4,    2,    1,    3,    2,    1,    2,    2,    2,    4,\n            1,    1,    1,    1,    1,    1,    1,    1,    3,    1,\n            1,    1,    0,    1,    1,    0,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    3,    5,    3,\n            3,    4,    1,    1,    3,    1,    1,    1,    1,    1,\n            3,    2,    3,    0,    1,    1,    3,    1,    1,    1,\n            1,    1,    1,    3,    1,    1,    1,    4,    4,    1,\n            4,    4,    0,    1,    1,    1,    3,    3,    1,    4,\n            2,    2,    1,    3,    1,    4,    4,    3,    3,    3,\n            3,    1,    3,    1,    1,    3,    1,    1,    4,    1,\n            1,    1,    3,    1,    1,    2,    1,    3,    4,    3,\n            2,    0,    2,    2,    1,    2,    1,    1,    1,    4,\n            3,    3,    3,    3,    6,    3,    1,    1,    2,    1\n    );\n\n    protected function initReduceCallbacks(): void {\n        $this->reduceCallbacks = [\n            0 => null,\n            1 => static function ($self, $stackPos) {\n                 $self->semValue = $self->handleNamespaces($self->semStack[$stackPos-(1-1)]);\n            },\n            2 => static function ($self, $stackPos) {\n                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;\n            },\n            3 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            4 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            5 => null,\n            6 => null,\n            7 => null,\n            8 => null,\n            9 => null,\n            10 => null,\n            11 => null,\n            12 => null,\n            13 => null,\n            14 => null,\n            15 => null,\n            16 => null,\n            17 => null,\n            18 => null,\n            19 => null,\n            20 => null,\n            21 => null,\n            22 => null,\n            23 => null,\n            24 => null,\n            25 => null,\n            26 => null,\n            27 => null,\n            28 => null,\n            29 => null,\n            30 => null,\n            31 => null,\n            32 => null,\n            33 => null,\n            34 => null,\n            35 => null,\n            36 => null,\n            37 => null,\n            38 => null,\n            39 => null,\n            40 => null,\n            41 => null,\n            42 => null,\n            43 => null,\n            44 => null,\n            45 => null,\n            46 => null,\n            47 => null,\n            48 => null,\n            49 => null,\n            50 => null,\n            51 => null,\n            52 => null,\n            53 => null,\n            54 => null,\n            55 => null,\n            56 => null,\n            57 => null,\n            58 => null,\n            59 => null,\n            60 => null,\n            61 => null,\n            62 => null,\n            63 => null,\n            64 => null,\n            65 => null,\n            66 => null,\n            67 => null,\n            68 => null,\n            69 => null,\n            70 => null,\n            71 => null,\n            72 => null,\n            73 => null,\n            74 => null,\n            75 => null,\n            76 => static function ($self, $stackPos) {\n                 $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])));\n            },\n            77 => null,\n            78 => null,\n            79 => null,\n            80 => null,\n            81 => null,\n            82 => null,\n            83 => null,\n            84 => null,\n            85 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            86 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            87 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            88 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            89 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            90 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            91 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            92 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            93 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            94 => null,\n            95 => static function ($self, $stackPos) {\n                 $self->semValue = new Name(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            96 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            97 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            98 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            99 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            100 => static function ($self, $stackPos) {\n                 $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));\n            },\n            101 => null,\n            102 => null,\n            103 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Attribute($self->semStack[$stackPos-(1-1)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            104 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            105 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            106 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            107 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\AttributeGroup($self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            108 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            109 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            110 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            111 => null,\n            112 => null,\n            113 => null,\n            114 => null,\n            115 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            116 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Namespace_($self->semStack[$stackPos-(3-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_SEMICOLON);\n            $self->checkNamespace($self->semValue);\n            },\n            117 => static function ($self, $stackPos) {\n                 $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]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_BRACED);\n            $self->checkNamespace($self->semValue);\n            },\n            118 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Namespace_(null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_BRACED);\n            $self->checkNamespace($self->semValue);\n            },\n            119 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Use_($self->semStack[$stackPos-(3-2)], Stmt\\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            120 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            121 => null,\n            122 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Const_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), []);\n            },\n            123 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Const_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(4-1)]);\n            $self->checkConstantAttributes($self->semValue);\n            },\n            124 => static function ($self, $stackPos) {\n                 $self->semValue = Stmt\\Use_::TYPE_FUNCTION;\n            },\n            125 => static function ($self, $stackPos) {\n                 $self->semValue = Stmt\\Use_::TYPE_CONSTANT;\n            },\n            126 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\GroupUse($self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-6)], $self->semStack[$stackPos-(8-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));\n            },\n            127 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\GroupUse($self->semStack[$stackPos-(7-2)], $self->semStack[$stackPos-(7-5)], Stmt\\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));\n            },\n            128 => null,\n            129 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            130 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            131 => null,\n            132 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            133 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            134 => null,\n            135 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            136 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            137 => static function ($self, $stackPos) {\n                 $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));\n            },\n            138 => static function ($self, $stackPos) {\n                 $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));\n            },\n            139 => static function ($self, $stackPos) {\n                 $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));\n            },\n            140 => static function ($self, $stackPos) {\n                 $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));\n            },\n            141 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->semValue->type = Stmt\\Use_::TYPE_NORMAL;\n            },\n            142 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)]; $self->semValue->type = $self->semStack[$stackPos-(2-1)];\n            },\n            143 => null,\n            144 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            145 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            146 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            147 => null,\n            148 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            149 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            150 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            151 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            152 => static function ($self, $stackPos) {\n                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;\n            },\n            153 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            154 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            155 => null,\n            156 => null,\n            157 => null,\n            158 => static function ($self, $stackPos) {\n                 throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            159 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Block($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            160 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            161 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            162 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            163 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            164 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            165 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            166 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Break_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            167 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Continue_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            168 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Return_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            169 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Global_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            170 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Static_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            171 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Echo_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            172 => static function ($self, $stackPos) {\n\n        $self->semValue = new Stmt\\InlineHTML($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n        $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos-(1-1)));\n\n            },\n            173 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Expression($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            174 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Unset_($self->semStack[$stackPos-(5-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));\n            },\n            175 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            176 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            177 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            178 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            179 => static function ($self, $stackPos) {\n                 $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);\n            },\n            180 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Goto_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            181 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Label($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            182 => static function ($self, $stackPos) {\n                 $self->semValue = null; /* means: no statement */\n            },\n            183 => null,\n            184 => static function ($self, $stackPos) {\n                 $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]);\n            },\n            185 => static function ($self, $stackPos) {\n                 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)]]; };\n            },\n            186 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            187 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            188 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            189 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            190 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            191 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            192 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Finally_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            193 => null,\n            194 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            195 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            196 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            197 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            198 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            199 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            200 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            201 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            202 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            203 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            204 => null,\n            205 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            206 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            207 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            208 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            209 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            210 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClass($self->semValue, $stackPos-(7-2));\n            },\n            211 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClass($self->semValue, $stackPos-(8-3));\n            },\n            212 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkInterface($self->semValue, $stackPos-(7-3));\n            },\n            213 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            214 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkEnum($self->semValue, $stackPos-(8-3));\n            },\n            215 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            216 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            217 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            218 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            219 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            220 => null,\n            221 => null,\n            222 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            223 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::ABSTRACT;\n            },\n            224 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            225 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            226 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            227 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            228 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            229 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            230 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            231 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            232 => null,\n            233 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            234 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            235 => null,\n            236 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            237 => null,\n            238 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            239 => static function ($self, $stackPos) {\n                 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)]]; };\n            },\n            240 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            241 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            242 => null,\n            243 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            244 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            245 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            246 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            247 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-3)];\n            },\n            248 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            249 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(5-3)];\n            },\n            250 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            251 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            252 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            253 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Case_(null, $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            254 => null,\n            255 => null,\n            256 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            257 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            258 => null,\n            259 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            260 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            261 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            262 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\MatchArm(null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            263 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            264 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            265 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            266 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            267 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            268 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            269 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            270 => static function ($self, $stackPos) {\n                 $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);\n            },\n            271 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            272 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Else_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            273 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            274 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Else_($self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);\n            },\n            275 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);\n            },\n            276 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(2-2)], true);\n            },\n            277 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);\n            },\n            278 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos-(1-1)]), false);\n            },\n            279 => null,\n            280 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            281 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            282 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            283 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            284 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            285 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC;\n            },\n            286 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED;\n            },\n            287 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE;\n            },\n            288 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC_SET;\n            },\n            289 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED_SET;\n            },\n            290 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE_SET;\n            },\n            291 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            292 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            293 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Param($self->semStack[$stackPos-(7-6)], null, $self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-4)], $self->semStack[$stackPos-(7-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(7-2)], $self->semStack[$stackPos-(7-1)], $self->semStack[$stackPos-(7-7)]);\n            $self->checkParam($self->semValue);\n            $self->addPropertyNameToHooks($self->semValue);\n            },\n            294 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Param($self->semStack[$stackPos-(9-6)], $self->semStack[$stackPos-(9-8)], $self->semStack[$stackPos-(9-3)], $self->semStack[$stackPos-(9-4)], $self->semStack[$stackPos-(9-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(9-2)], $self->semStack[$stackPos-(9-1)], $self->semStack[$stackPos-(9-9)]);\n            $self->checkParam($self->semValue);\n            $self->addPropertyNameToHooks($self->semValue);\n            },\n            295 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            296 => null,\n            297 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            298 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            299 => null,\n            300 => null,\n            301 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            302 => static function ($self, $stackPos) {\n                 $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos-(1-1)]);\n            },\n            303 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            304 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            305 => null,\n            306 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            307 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            308 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            309 => null,\n            310 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            311 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            312 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            313 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            314 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            315 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            316 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            317 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            318 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            319 => null,\n            320 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            321 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            322 => null,\n            323 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            324 => null,\n            325 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            326 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            327 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            328 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            329 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            330 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            331 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            332 => static function ($self, $stackPos) {\n                 $self->semValue = array(new Node\\Arg($self->semStack[$stackPos-(4-2)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));\n            },\n            333 => static function ($self, $stackPos) {\n                 $self->semValue = array(new Node\\Arg($self->semStack[$stackPos-(3-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)]);\n            },\n            334 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            335 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            336 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            337 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            338 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(2-2)], true, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            339 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(2-2)], false, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            340 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            341 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArgPlaceholder(null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            342 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            343 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArgPlaceholder($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            344 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(1-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            345 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            346 => null,\n            347 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            348 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            349 => null,\n            350 => null,\n            351 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            352 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            353 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\StaticVar($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            354 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            355 => static function ($self, $stackPos) {\n                 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)]; }\n            },\n            356 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            357 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            358 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            359 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClassConst($self->semValue, $stackPos-(5-2));\n            },\n            360 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClassConst($self->semValue, $stackPos-(6-2));\n            },\n            361 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClassMethod($self->semValue, $stackPos-(10-2));\n            },\n            362 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            363 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            364 => static function ($self, $stackPos) {\n                 $self->semValue = null; /* will be skipped */\n            },\n            365 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            366 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            367 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            368 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            369 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            370 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            371 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            372 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            373 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            374 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            375 => null,\n            376 => static function ($self, $stackPos) {\n                 $self->semValue = array(null, $self->semStack[$stackPos-(1-1)]);\n            },\n            377 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            378 => null,\n            379 => null,\n            380 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            381 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            382 => null,\n            383 => null,\n            384 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            385 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC;\n            },\n            386 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED;\n            },\n            387 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE;\n            },\n            388 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC_SET;\n            },\n            389 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED_SET;\n            },\n            390 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE_SET;\n            },\n            391 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::STATIC;\n            },\n            392 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::ABSTRACT;\n            },\n            393 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            394 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            395 => null,\n            396 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            397 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            398 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\VarLikeIdentifier(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            399 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyItem($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            400 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            401 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            402 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            403 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            404 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyHook($self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-5)], ['flags' => $self->semStack[$stackPos-(5-2)], 'byRef' => $self->semStack[$stackPos-(5-3)], 'params' => [], 'attrGroups' => $self->semStack[$stackPos-(5-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));\n            $self->checkPropertyHook($self->semValue, null);\n            },\n            405 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyHook($self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-8)], ['flags' => $self->semStack[$stackPos-(8-2)], 'byRef' => $self->semStack[$stackPos-(8-3)], 'params' => $self->semStack[$stackPos-(8-6)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));\n            $self->checkPropertyHook($self->semValue, $stackPos-(8-5));\n            },\n            406 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            407 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            408 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            409 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            410 => static function ($self, $stackPos) {\n                 $self->checkPropertyHookModifiers($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)];\n            },\n            411 => null,\n            412 => null,\n            413 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            414 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            415 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            416 => null,\n            417 => null,\n            418 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            419 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            420 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            421 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            422 => static function ($self, $stackPos) {\n                 $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]));\n            if (!$self->phpVersion->allowsAssignNewByReference()) {\n                $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));\n            }\n\n            },\n            423 => null,\n            424 => null,\n            425 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\FuncCall(new Node\\Name($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)],  $self->tokenEndStack[$stackPos-(2-1)])), $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            426 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Clone_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            427 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            428 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            429 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            430 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            431 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            432 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            433 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            434 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            435 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            436 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            437 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            438 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            439 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            440 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PostInc($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            441 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PreInc($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            442 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PostDec($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            443 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PreDec($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            444 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            445 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            446 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            447 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            448 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            449 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            450 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            451 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            452 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            453 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            454 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            455 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            456 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            457 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            458 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            459 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            460 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            461 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            462 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\UnaryPlus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            463 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\UnaryMinus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            464 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\BooleanNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            465 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\BitwiseNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            466 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            467 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            468 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            469 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            470 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            471 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            472 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            473 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            474 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            475 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            476 => static function ($self, $stackPos) {\n\n          $self->semValue = $self->semStack[$stackPos-(3-2)];\n          if ($self->semValue instanceof Expr\\ArrowFunction) {\n              $self->parenthesizedArrowFunctions->offsetSet($self->semValue);\n          }\n\n            },\n            477 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            478 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            479 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            480 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Isset_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            481 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Empty_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            482 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Include_($self->semStack[$stackPos-(2-2)], Expr\\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            483 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            484 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Eval_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            485 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Include_($self->semStack[$stackPos-(2-2)], Expr\\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            486 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            487 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Int_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            488 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Double($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            489 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\String_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            490 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            491 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            492 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Bool_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            493 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            494 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Void_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            495 => static function ($self, $stackPos) {\n                 $self->semValue = $self->createExitExpr($self->semStack[$stackPos-(2-1)], $stackPos-(2-1), $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            496 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ErrorSuppress($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            497 => null,\n            498 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ShellExec($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            499 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Print_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            500 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            501 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Yield_($self->semStack[$stackPos-(2-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            502 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            503 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\YieldFrom($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            504 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Throw_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            505 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            506 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            507 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            508 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            509 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            510 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            511 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            512 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            513 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClass($self->semValue[0], -1);\n            },\n            514 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            515 => static function ($self, $stackPos) {\n                 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]));\n            },\n            516 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\New_($self->semStack[$stackPos-(2-2)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            517 => null,\n            518 => null,\n            519 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            520 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-3)];\n            },\n            521 => null,\n            522 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            523 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            524 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            525 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            526 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            527 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            528 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            529 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            530 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            531 => null,\n            532 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            533 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            534 => static function ($self, $stackPos) {\n                 $self->semValue = new Name\\FullyQualified(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            535 => static function ($self, $stackPos) {\n                 $self->semValue = new Name\\Relative(substr($self->semStack[$stackPos-(1-1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            536 => null,\n            537 => null,\n            538 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            539 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;\n            },\n            540 => null,\n            541 => null,\n            542 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            543 => static function ($self, $stackPos) {\n                 $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()); } };\n            },\n            544 => static function ($self, $stackPos) {\n                 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)];\n            },\n            545 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            546 => null,\n            547 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ConstFetch($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            548 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Line($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            549 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\File($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            550 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Dir($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            551 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Class_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            552 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Trait_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            553 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Method($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            554 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Function_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            555 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            556 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Property($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            557 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            558 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            559 => static function ($self, $stackPos) {\n                 $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;\n            },\n            560 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\\Array_::KIND_SHORT;\n            $self->semValue = new Expr\\Array_($self->semStack[$stackPos-(3-2)], $attrs);\n            },\n            561 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\\Array_::KIND_LONG;\n            $self->semValue = new Expr\\Array_($self->semStack[$stackPos-(4-3)], $attrs);\n            $self->createdArrays->offsetSet($self->semValue);\n            },\n            562 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->offsetSet($self->semValue);\n            },\n            563 => static function ($self, $stackPos) {\n                 $self->semValue = Scalar\\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());\n            },\n            564 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Scalar\\String_::KIND_DOUBLE_QUOTED;\n            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);\n            },\n            565 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseLNumber($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals());\n            },\n            566 => static function ($self, $stackPos) {\n                 $self->semValue = Scalar\\Float_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            567 => null,\n            568 => null,\n            569 => null,\n            570 => static function ($self, $stackPos) {\n                 $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);\n            },\n            571 => static function ($self, $stackPos) {\n                 $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);\n            },\n            572 => static function ($self, $stackPos) {\n                 $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);\n            },\n            573 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            574 => null,\n            575 => null,\n            576 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            577 => null,\n            578 => null,\n            579 => null,\n            580 => null,\n            581 => null,\n            582 => null,\n            583 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            584 => null,\n            585 => null,\n            586 => null,\n            587 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            588 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            589 => null,\n            590 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            591 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            592 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            593 => null,\n            594 => null,\n            595 => null,\n            596 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            597 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            598 => null,\n            599 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            600 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            601 => static function ($self, $stackPos) {\n                 $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;\n            },\n            602 => static function ($self, $stackPos) {\n                 $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;\n            },\n            603 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            604 => null,\n            605 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            606 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            607 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            608 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            609 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            610 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            611 => null,\n            612 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            613 => null,\n            614 => null,\n            615 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            616 => null,\n            617 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;\n            },\n            618 => static function ($self, $stackPos) {\n                 $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);\n            $self->postprocessList($self->semValue);\n            },\n            619 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $end = count($self->semValue)-1; if ($self->semValue[$end]->value instanceof Expr\\Error) array_pop($self->semValue);\n            },\n            620 => null,\n            621 => static function ($self, $stackPos) {\n                 /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */\n            },\n            622 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            623 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            624 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            625 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(2-2)], null, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            626 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            627 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            628 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            629 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            630 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(2-2)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), true);\n            },\n            631 => static function ($self, $stackPos) {\n                 /* Create an Error node now to remember the position. We'll later either report an error,\n             or convert this into a null element, depending on whether this is a creation or destructuring context. */\n          $attrs = $self->createEmptyElemAttributes($self->tokenPos);\n          $self->semValue = new Node\\ArrayItem(new Expr\\Error($attrs), null, false, $attrs);\n            },\n            632 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            633 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            634 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            635 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)]);\n            },\n            636 => static function ($self, $stackPos) {\n                 $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);\n            },\n            637 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            638 => null,\n            639 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            640 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            641 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            642 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            643 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            644 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            645 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            646 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\String_($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            647 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseNumString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            648 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            649 => null,\n        ];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Parser/Php8.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\Parser;\n\nuse PhpParser\\Error;\nuse PhpParser\\Modifiers;\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Scalar;\nuse PhpParser\\Node\\Stmt;\n\n/* This is an automatically GENERATED file, which should not be manually edited.\n * Instead edit one of the following:\n *  * the grammar file grammar/php.y\n *  * the skeleton file grammar/parser.template\n *  * the preprocessing script grammar/rebuildParsers.php\n */\nclass Php8 extends \\PhpParser\\ParserAbstract\n{\n    public const YYERRTOK = 256;\n    public const T_VOID_CAST = 257;\n    public const T_THROW = 258;\n    public const T_INCLUDE = 259;\n    public const T_INCLUDE_ONCE = 260;\n    public const T_EVAL = 261;\n    public const T_REQUIRE = 262;\n    public const T_REQUIRE_ONCE = 263;\n    public const T_LOGICAL_OR = 264;\n    public const T_LOGICAL_XOR = 265;\n    public const T_LOGICAL_AND = 266;\n    public const T_PRINT = 267;\n    public const T_YIELD = 268;\n    public const T_DOUBLE_ARROW = 269;\n    public const T_YIELD_FROM = 270;\n    public const T_PLUS_EQUAL = 271;\n    public const T_MINUS_EQUAL = 272;\n    public const T_MUL_EQUAL = 273;\n    public const T_DIV_EQUAL = 274;\n    public const T_CONCAT_EQUAL = 275;\n    public const T_MOD_EQUAL = 276;\n    public const T_AND_EQUAL = 277;\n    public const T_OR_EQUAL = 278;\n    public const T_XOR_EQUAL = 279;\n    public const T_SL_EQUAL = 280;\n    public const T_SR_EQUAL = 281;\n    public const T_POW_EQUAL = 282;\n    public const T_COALESCE_EQUAL = 283;\n    public const T_COALESCE = 284;\n    public const T_BOOLEAN_OR = 285;\n    public const T_BOOLEAN_AND = 286;\n    public const T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG = 287;\n    public const T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG = 288;\n    public const T_IS_EQUAL = 289;\n    public const T_IS_NOT_EQUAL = 290;\n    public const T_IS_IDENTICAL = 291;\n    public const T_IS_NOT_IDENTICAL = 292;\n    public const T_SPACESHIP = 293;\n    public const T_IS_SMALLER_OR_EQUAL = 294;\n    public const T_IS_GREATER_OR_EQUAL = 295;\n    public const T_PIPE = 296;\n    public const T_SL = 297;\n    public const T_SR = 298;\n    public const T_INSTANCEOF = 299;\n    public const T_INC = 300;\n    public const T_DEC = 301;\n    public const T_INT_CAST = 302;\n    public const T_DOUBLE_CAST = 303;\n    public const T_STRING_CAST = 304;\n    public const T_ARRAY_CAST = 305;\n    public const T_OBJECT_CAST = 306;\n    public const T_BOOL_CAST = 307;\n    public const T_UNSET_CAST = 308;\n    public const T_POW = 309;\n    public const T_NEW = 310;\n    public const T_CLONE = 311;\n    public const T_EXIT = 312;\n    public const T_IF = 313;\n    public const T_ELSEIF = 314;\n    public const T_ELSE = 315;\n    public const T_ENDIF = 316;\n    public const T_LNUMBER = 317;\n    public const T_DNUMBER = 318;\n    public const T_STRING = 319;\n    public const T_STRING_VARNAME = 320;\n    public const T_VARIABLE = 321;\n    public const T_NUM_STRING = 322;\n    public const T_INLINE_HTML = 323;\n    public const T_ENCAPSED_AND_WHITESPACE = 324;\n    public const T_CONSTANT_ENCAPSED_STRING = 325;\n    public const T_ECHO = 326;\n    public const T_DO = 327;\n    public const T_WHILE = 328;\n    public const T_ENDWHILE = 329;\n    public const T_FOR = 330;\n    public const T_ENDFOR = 331;\n    public const T_FOREACH = 332;\n    public const T_ENDFOREACH = 333;\n    public const T_DECLARE = 334;\n    public const T_ENDDECLARE = 335;\n    public const T_AS = 336;\n    public const T_SWITCH = 337;\n    public const T_MATCH = 338;\n    public const T_ENDSWITCH = 339;\n    public const T_CASE = 340;\n    public const T_DEFAULT = 341;\n    public const T_BREAK = 342;\n    public const T_CONTINUE = 343;\n    public const T_GOTO = 344;\n    public const T_FUNCTION = 345;\n    public const T_FN = 346;\n    public const T_CONST = 347;\n    public const T_RETURN = 348;\n    public const T_TRY = 349;\n    public const T_CATCH = 350;\n    public const T_FINALLY = 351;\n    public const T_USE = 352;\n    public const T_INSTEADOF = 353;\n    public const T_GLOBAL = 354;\n    public const T_STATIC = 355;\n    public const T_ABSTRACT = 356;\n    public const T_FINAL = 357;\n    public const T_PRIVATE = 358;\n    public const T_PROTECTED = 359;\n    public const T_PUBLIC = 360;\n    public const T_READONLY = 361;\n    public const T_PUBLIC_SET = 362;\n    public const T_PROTECTED_SET = 363;\n    public const T_PRIVATE_SET = 364;\n    public const T_VAR = 365;\n    public const T_UNSET = 366;\n    public const T_ISSET = 367;\n    public const T_EMPTY = 368;\n    public const T_HALT_COMPILER = 369;\n    public const T_CLASS = 370;\n    public const T_TRAIT = 371;\n    public const T_INTERFACE = 372;\n    public const T_ENUM = 373;\n    public const T_EXTENDS = 374;\n    public const T_IMPLEMENTS = 375;\n    public const T_OBJECT_OPERATOR = 376;\n    public const T_NULLSAFE_OBJECT_OPERATOR = 377;\n    public const T_LIST = 378;\n    public const T_ARRAY = 379;\n    public const T_CALLABLE = 380;\n    public const T_CLASS_C = 381;\n    public const T_TRAIT_C = 382;\n    public const T_METHOD_C = 383;\n    public const T_FUNC_C = 384;\n    public const T_PROPERTY_C = 385;\n    public const T_LINE = 386;\n    public const T_FILE = 387;\n    public const T_START_HEREDOC = 388;\n    public const T_END_HEREDOC = 389;\n    public const T_DOLLAR_OPEN_CURLY_BRACES = 390;\n    public const T_CURLY_OPEN = 391;\n    public const T_PAAMAYIM_NEKUDOTAYIM = 392;\n    public const T_NAMESPACE = 393;\n    public const T_NS_C = 394;\n    public const T_DIR = 395;\n    public const T_NS_SEPARATOR = 396;\n    public const T_ELLIPSIS = 397;\n    public const T_NAME_FULLY_QUALIFIED = 398;\n    public const T_NAME_QUALIFIED = 399;\n    public const T_NAME_RELATIVE = 400;\n    public const T_ATTRIBUTE = 401;\n\n    protected int $tokenToSymbolMapSize = 402;\n    protected int $actionTableSize = 1644;\n    protected int $gotoTableSize = 717;\n\n    protected int $invalidSymbol = 174;\n    protected int $errorSymbol = 1;\n    protected int $defaultAction = -32766;\n    protected int $unexpectedTokenRule = 32767;\n\n    protected int $YY2TBLSTATE = 451;\n    protected int $numNonLeafStates = 764;\n\n    protected array $symbolToName = array(\n        \"EOF\",\n        \"error\",\n        \"T_VOID_CAST\",\n        \"T_THROW\",\n        \"T_INCLUDE\",\n        \"T_INCLUDE_ONCE\",\n        \"T_EVAL\",\n        \"T_REQUIRE\",\n        \"T_REQUIRE_ONCE\",\n        \"','\",\n        \"T_LOGICAL_OR\",\n        \"T_LOGICAL_XOR\",\n        \"T_LOGICAL_AND\",\n        \"T_PRINT\",\n        \"T_YIELD\",\n        \"T_DOUBLE_ARROW\",\n        \"T_YIELD_FROM\",\n        \"'='\",\n        \"T_PLUS_EQUAL\",\n        \"T_MINUS_EQUAL\",\n        \"T_MUL_EQUAL\",\n        \"T_DIV_EQUAL\",\n        \"T_CONCAT_EQUAL\",\n        \"T_MOD_EQUAL\",\n        \"T_AND_EQUAL\",\n        \"T_OR_EQUAL\",\n        \"T_XOR_EQUAL\",\n        \"T_SL_EQUAL\",\n        \"T_SR_EQUAL\",\n        \"T_POW_EQUAL\",\n        \"T_COALESCE_EQUAL\",\n        \"'?'\",\n        \"':'\",\n        \"T_COALESCE\",\n        \"T_BOOLEAN_OR\",\n        \"T_BOOLEAN_AND\",\n        \"'|'\",\n        \"'^'\",\n        \"T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG\",\n        \"T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG\",\n        \"T_IS_EQUAL\",\n        \"T_IS_NOT_EQUAL\",\n        \"T_IS_IDENTICAL\",\n        \"T_IS_NOT_IDENTICAL\",\n        \"T_SPACESHIP\",\n        \"'<'\",\n        \"T_IS_SMALLER_OR_EQUAL\",\n        \"'>'\",\n        \"T_IS_GREATER_OR_EQUAL\",\n        \"T_PIPE\",\n        \"'.'\",\n        \"T_SL\",\n        \"T_SR\",\n        \"'+'\",\n        \"'-'\",\n        \"'*'\",\n        \"'/'\",\n        \"'%'\",\n        \"'!'\",\n        \"T_INSTANCEOF\",\n        \"'~'\",\n        \"T_INC\",\n        \"T_DEC\",\n        \"T_INT_CAST\",\n        \"T_DOUBLE_CAST\",\n        \"T_STRING_CAST\",\n        \"T_ARRAY_CAST\",\n        \"T_OBJECT_CAST\",\n        \"T_BOOL_CAST\",\n        \"T_UNSET_CAST\",\n        \"'@'\",\n        \"T_POW\",\n        \"'['\",\n        \"T_NEW\",\n        \"T_CLONE\",\n        \"T_EXIT\",\n        \"T_IF\",\n        \"T_ELSEIF\",\n        \"T_ELSE\",\n        \"T_ENDIF\",\n        \"T_LNUMBER\",\n        \"T_DNUMBER\",\n        \"T_STRING\",\n        \"T_STRING_VARNAME\",\n        \"T_VARIABLE\",\n        \"T_NUM_STRING\",\n        \"T_INLINE_HTML\",\n        \"T_ENCAPSED_AND_WHITESPACE\",\n        \"T_CONSTANT_ENCAPSED_STRING\",\n        \"T_ECHO\",\n        \"T_DO\",\n        \"T_WHILE\",\n        \"T_ENDWHILE\",\n        \"T_FOR\",\n        \"T_ENDFOR\",\n        \"T_FOREACH\",\n        \"T_ENDFOREACH\",\n        \"T_DECLARE\",\n        \"T_ENDDECLARE\",\n        \"T_AS\",\n        \"T_SWITCH\",\n        \"T_MATCH\",\n        \"T_ENDSWITCH\",\n        \"T_CASE\",\n        \"T_DEFAULT\",\n        \"T_BREAK\",\n        \"T_CONTINUE\",\n        \"T_GOTO\",\n        \"T_FUNCTION\",\n        \"T_FN\",\n        \"T_CONST\",\n        \"T_RETURN\",\n        \"T_TRY\",\n        \"T_CATCH\",\n        \"T_FINALLY\",\n        \"T_USE\",\n        \"T_INSTEADOF\",\n        \"T_GLOBAL\",\n        \"T_STATIC\",\n        \"T_ABSTRACT\",\n        \"T_FINAL\",\n        \"T_PRIVATE\",\n        \"T_PROTECTED\",\n        \"T_PUBLIC\",\n        \"T_READONLY\",\n        \"T_PUBLIC_SET\",\n        \"T_PROTECTED_SET\",\n        \"T_PRIVATE_SET\",\n        \"T_VAR\",\n        \"T_UNSET\",\n        \"T_ISSET\",\n        \"T_EMPTY\",\n        \"T_HALT_COMPILER\",\n        \"T_CLASS\",\n        \"T_TRAIT\",\n        \"T_INTERFACE\",\n        \"T_ENUM\",\n        \"T_EXTENDS\",\n        \"T_IMPLEMENTS\",\n        \"T_OBJECT_OPERATOR\",\n        \"T_NULLSAFE_OBJECT_OPERATOR\",\n        \"T_LIST\",\n        \"T_ARRAY\",\n        \"T_CALLABLE\",\n        \"T_CLASS_C\",\n        \"T_TRAIT_C\",\n        \"T_METHOD_C\",\n        \"T_FUNC_C\",\n        \"T_PROPERTY_C\",\n        \"T_LINE\",\n        \"T_FILE\",\n        \"T_START_HEREDOC\",\n        \"T_END_HEREDOC\",\n        \"T_DOLLAR_OPEN_CURLY_BRACES\",\n        \"T_CURLY_OPEN\",\n        \"T_PAAMAYIM_NEKUDOTAYIM\",\n        \"T_NAMESPACE\",\n        \"T_NS_C\",\n        \"T_DIR\",\n        \"T_NS_SEPARATOR\",\n        \"T_ELLIPSIS\",\n        \"T_NAME_FULLY_QUALIFIED\",\n        \"T_NAME_QUALIFIED\",\n        \"T_NAME_RELATIVE\",\n        \"T_ATTRIBUTE\",\n        \"';'\",\n        \"']'\",\n        \"'('\",\n        \"')'\",\n        \"'{'\",\n        \"'}'\",\n        \"'`'\",\n        \"'\\\"'\",\n        \"'$'\"\n    );\n\n    protected array $tokenToSymbol = array(\n            0,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,   58,  172,  174,  173,   57,  174,  174,\n          167,  168,   55,   53,    9,   54,   50,   56,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,   32,  165,\n           45,   17,   47,   31,   70,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,   72,  174,  166,   37,  174,  171,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  169,   36,  170,   60,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,  174,  174,  174,  174,\n          174,  174,  174,  174,  174,  174,    1,    2,    3,    4,\n            5,    6,    7,    8,   10,   11,   12,   13,   14,   15,\n           16,   18,   19,   20,   21,   22,   23,   24,   25,   26,\n           27,   28,   29,   30,   33,   34,   35,   38,   39,   40,\n           41,   42,   43,   44,   46,   48,   49,   51,   52,   59,\n           61,   62,   63,   64,   65,   66,   67,   68,   69,   71,\n           73,   74,   75,   76,   77,   78,   79,   80,   81,   82,\n           83,   84,   85,   86,   87,   88,   89,   90,   91,   92,\n           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,\n          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,\n          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,\n          123,  124,  125,  126,  127,  128,  129,  130,  131,  132,\n          133,  134,  135,  136,  137,  138,  139,  140,  141,  142,\n          143,  144,  145,  146,  147,  148,  149,  150,  151,  152,\n          153,  154,  155,  156,  157,  158,  159,  160,  161,  162,\n          163,  164\n    );\n\n    protected array $action = array(\n          133,  134,  135,  581,  136,  137, 1059,  776,  777,  778,\n          138,   41,  394,  395,  454,  501,-32766,-32766,-32766,  971,\n          970,  851,  439,    0,  987,  988,  627,  851, 1105,  989,\n        -32766,-32766,-32766,  862,-32766,  770,  769,-32766,  983,-32766,\n        -32766,-32766,-32766,-32766,-32766,-32766,-32767,-32767,-32767,-32767,\n        -32767,-32766,   27,-32766,-32766,-32766,  779, 1156, 1157, 1158,\n         1152, 1151, 1150, 1159, 1153, 1154, 1155, -338,  304,  969,\n          270,   54,  397,  783,  784,  785,  786, 1145,  -85,  440,\n          860,-32766,-32766, 1401,  299, 1107,  840,  787,  788,  789,\n          790,  791,  792,  793,  794,  795,  796,  816,  582,  817,\n          818,  819,  820,  808,  809,  352,  353,  811,  812,  797,\n          798,  799,  801,  802,  803,  367,  843,  844,  845,  846,\n          847,  583, 1299,  610,  244,  804,  805,  584,  585, -195,\n          828,  826,  827,  839,  823,  824, 1299,    4,  586,  587,\n          822,  588,  589,  590,  591,  -85,  592,  593, 1018,   39,\n          253, -194,  502,  825,  594,  595,  853,  139,  436,  133,\n          134,  135,  581,  136,  137, 1094,  776,  777,  778,  138,\n           41,-32766,  436, 1056, 1051, 1050, 1049, 1055, 1052, 1053,\n         1054,-32766,-32766,-32766,-32766,-32766,-32766, 1105,  245,  132,\n        -32766,-32766,-32766,  165,  770,  769, 1068,  861,-32766,-32766,\n        -32766, 1382,-32766,-32766,-32766,-32766,-32766,-32766,-32766,-32766,\n        -32766,-32766,    5,-32766,-32766,  779,-32766,-32766,-32766,-32766,\n          298,-32766,-32766,-32766,-32766,-32766, -338,-32766, 1326,  270,\n           54,  397,  783,  784,  785,  786,  855,-32766,  440,-32766,\n        -32766,-32766,-32766,  733,  577,  840,  787,  788,  789,  790,\n          791,  792,  793,  794,  795,  796,  816,  582,  817,  818,\n          819,  820,  808,  809,  352,  353,  811,  812,  797,  798,\n          799,  801,  802,  803,  367,  843,  844,  845,  846,  847,\n          583, 1019,  851, -584,  804,  805,  584,  585, -195,  828,\n          826,  827,  839,  823,  824,  -50,  440,  586,  587,  822,\n          588,  589,  590,  591, -582,  592,  593,  394,  395, 1338,\n         -194,  860,  825,  594,  595,   29,  139,  439,  133,  134,\n          135,  581,  136,  137, 1092,  776,  777,  778,  138,   41,\n         1156, 1157, 1158, 1152, 1151, 1150, 1159, 1153, 1154, 1155,\n            3, -275, 1367, 1172, 1386, 1299, 1105,  751,   38, 1091,\n         -584, -584, 1385,  770,  769,-32767,-32767,-32767,-32767,  107,\n          108,  109,  110,  304,  111,  112,  113,  114,  115,  145,\n          282, -582, -582,  331,  779, 1301, 1300, 1302,  152,  293,\n          299,  436,  116,  161, 1131,  396,  395, -582,  270,   54,\n          397,  783,  784,  785,  786,  439,  144,  440,  140, -588,\n          331,  108,  109,  110,  840,  787,  788,  789,  790,  791,\n          792,  793,  794,  795,  796,  816,  582,  817,  818,  819,\n          820,  808,  809,  352,  353,  811,  812,  797,  798,  799,\n          801,  802,  803,  367,  843,  844,  845,  846,  847,  583,\n         1299, -580,  148,  804,  805,  584,  585,  856,  828,  826,\n          827,  839,  823,  824,  143, -581,  586,  587,  822,  588,\n          589,  590,  591, -579,  592,  593, 1065,-32766,-32766,-32766,\n        -32766,  825,  594,  595, -578,  139, 1297,  133,  134,  135,\n          581,  136,  137, 1096,  776,  777,  778,  138,   41,-32766,\n         1299, 1068, 1068,   52,-32766,-32766,-32766,  633, 1130,  322,\n         1067,  888,  759,  889, 1299, 1105,  256, 1299, -580, -580,\n           87,  315,  770,  769,  331,  289,  298,  967,  319, 1301,\n         1300, 1302, -581, -581, -580, 1411,  436,  857, 1412,  507,\n         -579, -579,  332,  779,-32766,  761, -587, 1065, -581,  328,\n          436, -578, -578,  436,  770,  769, -579,  270,   54,  397,\n          783,  784,  785,  786,  859,  348,  440, -578, -586, 1068,\n          305,  306, 1068,  840,  787,  788,  789,  790,  791,  792,\n          793,  794,  795,  796,  816,  582,  817,  818,  819,  820,\n          808,  809,  352,  353,  811,  812,  797,  798,  799,  801,\n          802,  803,  367,  843,  844,  845,  846,  847,  583,  487,\n          488,  349,  804,  805,  584,  585,  153,  828,  826,  827,\n          839,  823,  824,   53,  382,  586,  587,  822,  588,  589,\n          590,  591,  155,  592,  593,  -78,   88,   89,   90,  388,\n          825,  594,  595,  404,  139,  800,  771,  772,  773,  774,\n          775,  156,  776,  777,  778,  813,  814,   40,  458,   91,\n           92,   93,   94,   95,   96,   97,   98,   99,  100,  101,\n          102,  103,  104,  105,  106,  107,  108,  109,  110,  111,\n          112,  113,  114,  115, 1306,  282,  476,  477,  478, 1299,\n          307,  308, -383,  459, -383,  746,  406,  116,   10,  460,\n          888,  779,  889, -620,  461, -620,  387,  109,  110,  866,\n        -32766,-32766,  676,   23,  157,  780,  781,  782,  783,  784,\n          785,  786,  695,  696,  849,  436,  151,  422,  392,  393,\n          159,  840,  787,  788,  789,  790,  791,  792,  793,  794,\n          795,  796,  816,  838,  817,  818,  819,  820,  808,  809,\n          810,  837,  811,  812,  797,  798,  799,  801,  802,  803,\n          842,  843,  844,  845,  846,  847,  848,  860,-32766, 1065,\n          804,  805,  806,  807,    2,  828,  826,  827,  839,  823,\n          824,  398,  399,  815,  821,  822,  829,  830,  832,  831,\n           36,  833,  834, 1068, 1068,  667,  668,  -58,  825,  836,\n          835,   55,   56,   57,   58,  533,   59,   60,  -57,  130,\n          770,  769,   61,   62,  131,   63,  -87,  298,  289,  141,\n          142,  147,  160,  162,  163,-32766,  770,  769,  164, -309,\n          -84,   35,  117,  118,  119,  120,  121,  122,  123,  124,\n          125,  126,  127,  128,  129,  -78, -305,  -73,  -72,  -71,\n           80,  -70,   64,   65, 1299,  -69,  331,   66,  -68,   67,\n          250,  251,   68,   69,   70,   71,   72,   73,   74,   75,\n         1299,   31,  275,   48,  456, 1206, 1208,  -67,  -66, 1332,\n         1333,  535,  -65,  860,  -46,  -18, -578, 1330,   42,  280,\n          436,  290,  747,  750,  945,  150,  294,  282,  946,  116,\n          541,  287,  288,  291,  292,  337,  436,  391,  390,  295,\n          300,  301,  149,  963,  705,  851,  720,  347,-32766,  677,\n          860, 1163,  682, 1292, 1413,  698,  722,  683,  312,  545,\n          546,  309,   79,  597,  984,  665, -544,  318,-32766, 1337,\n          548,  549,   13, 1318, 1319, 1320, 1321, 1323, 1315, 1316,\n          303,  699, 1327, -578, -578,  965, 1322, 1317, -278,  310,\n         1301, 1300, 1302,  304,   -4,  946,   76,  603,  631, -578,\n          326,  327,  331,  534, -154, -154, -154,  484,  512,  859,\n            0,    0, 1339,  936,    0,    0,   46,   22,  536, -154,\n          537, -154,  538, -154,  539, -154, -534,  540,    0,   11,\n            0,    0,   49,   50,  462,  389,   30,    0,   51,  542,\n          386,  304,    0,   44,  380,    0,  987,  988,    0,   45,\n          946,  543,    0,    0,    0,    0,  544,    0,    0,  922,\n          983, -110, -110, -110,  421,  756,    0,    0,    0,    0,\n          534,  757,  879, -276,    0,  927, 1028, 1005, 1012, 1002,\n          936, 1013,  925,   46,   22,  536, 1000,  537, 1134,  538,\n         1137,  539,  948, 1138,  540, 1135,  731, -154, 1174,   49,\n           50,  462,  389, 1136,  452,   51,  542, 1142, -614,  302,\n          871,  380, 1354,  987,  988, 1371, 1404,  670,  543, -613,\n         -612,  946, -588,  544, -587,  534,  547,  983, -110, -110,\n         -110, -586, -585, -528,    1,  936,   32,   33,   46,   22,\n          536,   43,  537,   47,  538,   77,  539,   81,   82,  540,\n           21, -253, -253, -253,   49,   50,  462,  389,   83,  948,\n           51,  542,   84,  731,   -4,   85,  380,   86,  987,  988,\n          146,  154,  946,  543,  158,  248,  333,  368,  544,  369,\n          370,  922,  983, -110, -110, -110,  371,  372,  373,  374,\n          375,  376,  377,  378,  381,  453,  534,  576, 1306,  379,\n          770,  769, -275,  736,   15,   16,  936,   17,   18,   46,\n           22,  536,   20,  537,  948,  538,  362,  539,  731, -253,\n          540,  420, -252, -252, -252,   49,   50,  462,  389,  -16,\n          503,   51,  542,  504,   31,  276,  511,  380,  514,  987,\n          988,  515,  516,  517,  543,  521,  860,  534,  522,  544,\n         1330,  523,  922,  983, -110, -110, -110,  936,  530,  608,\n           46,   22,  536,  946,  537,  715,  538, 1247,  539, 1328,\n         1095,  540, 1093, 1074, 1287, 1070,   49,   50,  462, -280,\n         -102,  860,   51,  542,   14,  948, 1292,   19,  380,  731,\n         -252,   24,  322,  419,  737,  622,  946,  628,  656,  721,\n          544, 1251, 1305,  548,  549, 1248, 1318, 1319, 1320, 1321,\n         1323, 1315, 1316, 1383,  425,   37, -110, -110,  325, 1322,\n         1317, -110,  383,  732,  735,  739,  740,  738,  742,   78,\n         -110,  753,  743,  744,  327,  331,  948,  745,  534,-32766,\n          731,  749,  761,  734,  762,  946,  923, 1408,  936, 1410,\n          882,   46,   22,  536,  881,  537,  977,  538, 1020,  539,\n         1409,  304,  540,  976,   80,  974,  975,   49,   50,  462,\n          331,  534,  978,   51,  542, 1280,  741,  956,  946,  380,\n          966,  936,  954, 1173,   46,   22,  536, 1169,  537, 1123,\n          538,  544,  539, 1010, 1011,  540,  654, 1407, 1365, 1380,\n           49,   50,  462, 1265,  331, 1331,   51,  542,    0,  748,\n            0,  946,  380,    0,    0,    0,    0,    0,    0,    0,\n          534,    0,    0,    0,  544,    0,    0,  948,    0,    0,\n          936,  731,    0,   46,   22,  536,    0,  537,    0,  538,\n         1306,  539,    0,    0,  540,    0,    0,    0,    0,   49,\n           50,  462,    0,  534,    0,   51,  542,    0,    0,    0,\n         1004,  380,    0,  936,  731,    0,   46,   22,  536,    0,\n          537,    0,  538,  544,  539,    0,    0,  540,    0,    0,\n            0,    0,   49,   50,  462,    0,  534,    0,   51,  542,\n            0,    0,   31,  275,  380,    0,  936,    0,    0,   46,\n           22,  536,    0,  537,  860,  538,  544,  539, 1330,  948,\n          540,    0,    0,  731, 1129,   49,   50,  462,    0,    0,\n            0,   51,  542,  860,   31,  276,    0,  380,    0,    0,\n            0,  293,    0,    0,    0,    0,  860,    0,    0,  544,\n         1330,    0,  948,    0, 1292,    0,  731,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0, -110, -110,\n            0,    0,  549, -110, 1318, 1319, 1320, 1321, 1323, 1315,\n         1316,    0, -110,    0,    0,  948, 1292, 1322, 1317,  731,\n            0,-32766,  709,    0,    0,    0,    0,   78,    0,    0,\n            0,    0,  327,  331,  549,    0, 1318, 1319, 1320, 1321,\n         1323, 1315, 1316,  304,    0,    0,   80,    0,    0, 1322,\n         1317,    0,  331,    0,    0,    0, -110,    0,  710,   78,\n            0, -110,    0, -110,  327,  331,    0,    0,  311,    0,\n            0, -110, -110, -110, -110, -110, -110, -110, -110, -110,\n         -110, -110,  711,  712,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0, 1301, 1300, 1302,    0,    0,    0,  289,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0, -357\n    );\n\n    protected array $actionCheck = array(\n            3,    4,    5,    6,    7,    8,    1,   10,   11,   12,\n           13,   14,  108,  109,  110,   32,   10,   11,   12,   74,\n           75,   82,  118,    0,  119,  120,    1,   82,   31,  124,\n           10,   11,   12,    1,   10,   38,   39,   31,  133,   33,\n           34,   35,   36,   37,   38,   39,   40,   41,   42,   43,\n           44,   31,  103,   33,   34,   35,   59,  118,  119,  120,\n          121,  122,  123,  124,  125,  126,  127,    9,  164,  124,\n           73,   74,   75,   76,   77,   78,   79,  128,   32,   82,\n           84,   10,   11,   87,   31,   31,   89,   90,   91,   92,\n           93,   94,   95,   96,   97,   98,   99,  100,  101,  102,\n          103,  104,  105,  106,  107,  108,  109,  110,  111,  112,\n          113,  114,  115,  116,  117,  118,  119,  120,  121,  122,\n          123,  124,   82,   83,   99,  128,  129,  130,  131,    9,\n          133,  134,  135,  136,  137,  138,   82,    9,  141,  142,\n          143,  144,  145,  146,  147,   99,  149,  150,   32,  153,\n          154,    9,  169,  156,  157,  158,   82,  160,  118,    3,\n            4,    5,    6,    7,    8,  168,   10,   11,   12,   13,\n           14,  118,  118,  120,  121,  122,  123,  124,  125,  126,\n          127,   10,   11,   12,   10,   11,   12,   31,   15,   15,\n           10,   11,   12,   15,   38,   39,  143,  165,   10,   11,\n           12,    1,   31,  118,   33,   34,   35,   36,   37,   38,\n           39,   31,    9,   33,   34,   59,   10,   11,   12,   31,\n          167,   33,   34,   35,   36,   37,  168,  142,    1,   73,\n           74,   75,   76,   77,   78,   79,  162,   31,   82,   33,\n           34,   35,   36,  169,   87,   89,   90,   91,   92,   93,\n           94,   95,   96,   97,   98,   99,  100,  101,  102,  103,\n          104,  105,  106,  107,  108,  109,  110,  111,  112,  113,\n          114,  115,  116,  117,  118,  119,  120,  121,  122,  123,\n          124,  165,   82,   72,  128,  129,  130,  131,  168,  133,\n          134,  135,  136,  137,  138,   32,   82,  141,  142,  143,\n          144,  145,  146,  147,   72,  149,  150,  108,  109,  152,\n          168,   84,  156,  157,  158,    9,  160,  118,    3,    4,\n            5,    6,    7,    8,  168,   10,   11,   12,   13,   14,\n          118,  119,  120,  121,  122,  123,  124,  125,  126,  127,\n            9,  168,    1,  165,    1,   82,   31,  169,    9,    1,\n          139,  140,    9,   38,   39,   45,   46,   47,   48,   49,\n           50,   51,   52,  164,   53,   54,   55,   56,   57,  169,\n           59,  139,  140,  173,   59,  161,  162,  163,   15,   31,\n           31,  118,   71,   17,  170,  108,  109,  155,   73,   74,\n           75,   76,   77,   78,   79,  118,  169,   82,    9,  167,\n          173,   50,   51,   52,   89,   90,   91,   92,   93,   94,\n           95,   96,   97,   98,   99,  100,  101,  102,  103,  104,\n          105,  106,  107,  108,  109,  110,  111,  112,  113,  114,\n          115,  116,  117,  118,  119,  120,  121,  122,  123,  124,\n           82,   72,    9,  128,  129,  130,  131,   82,  133,  134,\n          135,  136,  137,  138,   32,   72,  141,  142,  143,  144,\n          145,  146,  147,   72,  149,  150,  118,  118,   10,   11,\n           12,  156,  157,  158,   72,  160,  118,    3,    4,    5,\n            6,    7,    8,  168,   10,   11,   12,   13,   14,   31,\n           82,  143,  143,   72,   10,   11,   12,   54,  165,  168,\n          142,  108,  169,  110,   82,   31,    9,   82,  139,  140,\n          169,    9,   38,   39,  173,  167,  167,    1,    9,  161,\n          162,  163,  139,  140,  155,   82,  118,  162,   85,  104,\n          139,  140,   72,   59,  118,  169,  167,  118,  155,    9,\n          118,  139,  140,  118,   38,   39,  155,   73,   74,   75,\n           76,   77,   78,   79,  161,    9,   82,  155,  167,  143,\n          139,  140,  143,   89,   90,   91,   92,   93,   94,   95,\n           96,   97,   98,   99,  100,  101,  102,  103,  104,  105,\n          106,  107,  108,  109,  110,  111,  112,  113,  114,  115,\n          116,  117,  118,  119,  120,  121,  122,  123,  124,  139,\n          140,    9,  128,  129,  130,  131,   15,  133,  134,  135,\n          136,  137,  138,   72,    9,  141,  142,  143,  144,  145,\n          146,  147,   15,  149,  150,   17,   10,   11,   12,    9,\n          156,  157,  158,    9,  160,    3,    4,    5,    6,    7,\n            8,   15,   10,   11,   12,   13,   14,   31,    9,   33,\n           34,   35,   36,   37,   38,   39,   40,   41,   42,   43,\n           44,   45,   46,   47,   48,   49,   50,   51,   52,   53,\n           54,   55,   56,   57,    1,   59,  134,  135,  136,   82,\n          139,  140,  108,    9,  110,  169,  108,   71,  110,    9,\n          108,   59,  110,  166,    9,  168,  155,   51,   52,    9,\n           53,   54,   77,   78,   15,   73,   74,   75,   76,   77,\n           78,   79,   77,   78,   82,  118,  103,  104,  108,  109,\n           15,   89,   90,   91,   92,   93,   94,   95,   96,   97,\n           98,   99,  100,  101,  102,  103,  104,  105,  106,  107,\n          108,  109,  110,  111,  112,  113,  114,  115,  116,  117,\n          118,  119,  120,  121,  122,  123,  124,   84,  118,  118,\n          128,  129,  130,  131,  167,  133,  134,  135,  136,  137,\n          138,  108,  109,  141,  142,  143,  144,  145,  146,  147,\n           15,  149,  150,  143,  143,  113,  114,   17,  156,  157,\n          158,    2,    3,    4,    5,    6,    7,    8,   17,   17,\n           38,   39,   13,   14,   17,   16,   32,  167,  167,   17,\n           17,   17,   17,   17,   17,  142,   38,   39,   17,   36,\n           32,   17,   18,   19,   20,   21,   22,   23,   24,   25,\n           26,   27,   28,   29,   30,   32,   36,   32,   32,   32,\n          167,   32,   53,   54,   82,   32,  173,   58,   32,   60,\n           61,   62,   63,   64,   65,   66,   67,   68,   69,   70,\n           82,   72,   73,   74,   75,   61,   62,   32,   32,   80,\n           81,   82,   32,   84,   32,   32,   72,   88,   32,   32,\n          118,   32,   32,   32,   32,   32,   38,   59,    1,   71,\n          101,   36,   36,   36,   36,   36,  118,  108,  109,   38,\n           38,   38,   72,   39,   79,   82,   82,  118,   87,   92,\n           84,   84,   98,  124,   85,   96,   94,  102,  116,  130,\n          131,  137,  160,   91,  133,  115,  155,  137,  142,  152,\n          141,  142,   99,  144,  145,  146,  147,  148,  149,  150,\n          151,  102,  166,  139,  140,  160,  157,  158,  168,  138,\n          161,  162,  163,  164,    0,    1,  167,  159,  159,  155,\n          171,  172,  173,   76,   77,   78,   79,   99,   99,  161,\n           -1,   -1,  152,   86,   -1,   -1,   89,   90,   91,   92,\n           93,   94,   95,   96,   97,   98,  155,  100,   -1,  155,\n           -1,   -1,  105,  106,  107,  108,  155,   -1,  111,  112,\n          155,  164,   -1,  165,  117,   -1,  119,  120,   -1,  165,\n            1,  124,   -1,   -1,   -1,   -1,  129,   -1,   -1,  132,\n          133,  134,  135,  136,  170,  165,   -1,   -1,   -1,   -1,\n           76,  165,  165,  168,   -1,  165,  165,  165,  165,  165,\n           86,  165,  165,   89,   90,   91,  165,   93,  165,   95,\n          165,   97,  165,  165,  100,  165,  169,  170,  165,  105,\n          106,  107,  108,  165,  110,  111,  112,  165,  167,  115,\n          166,  117,  166,  119,  120,  166,  166,  166,  124,  167,\n          167,    1,  167,  129,  167,   76,  132,  133,  134,  135,\n          136,  167,  167,  167,  167,   86,  167,  167,   89,   90,\n           91,  167,   93,  167,   95,  167,   97,  167,  167,  100,\n          156,  102,  103,  104,  105,  106,  107,  108,  167,  165,\n          111,  112,  167,  169,  170,  167,  117,  167,  119,  120,\n          167,  167,    1,  124,  167,  167,  167,  167,  129,  167,\n          167,  132,  133,  134,  135,  136,  167,  167,  167,  167,\n          167,  167,  167,  167,  167,  167,   76,  167,    1,  167,\n           38,   39,  168,   32,  168,  168,   86,  168,  168,   89,\n           90,   91,  168,   93,  165,   95,  168,   97,  169,  170,\n          100,  168,  102,  103,  104,  105,  106,  107,  108,   32,\n          168,  111,  112,  168,   72,   73,  168,  117,  168,  119,\n          120,  168,  168,  168,  124,  168,   84,   76,  168,  129,\n           88,  168,  132,  133,  134,  135,  136,   86,  168,  168,\n           89,   90,   91,    1,   93,  168,   95,  168,   97,  168,\n          168,  100,  168,  168,  168,  168,  105,  106,  107,  168,\n          168,   84,  111,  112,  168,  165,  124,  168,  117,  169,\n          170,  168,  168,  168,   32,  168,    1,  168,  168,  168,\n          129,  168,  168,  141,  142,  168,  144,  145,  146,  147,\n          148,  149,  150,  168,  170,  169,  119,  120,  169,  157,\n          158,  124,  169,  169,  169,  169,  169,   32,  169,  167,\n          133,  170,  169,  169,  172,  173,  165,  169,   76,  142,\n          169,  169,  169,  169,  169,    1,  170,  170,   86,  170,\n          170,   89,   90,   91,  170,   93,  170,   95,  170,   97,\n          170,  164,  100,  170,  167,  170,  170,  105,  106,  107,\n          173,   76,  170,  111,  112,  170,   32,  170,    1,  117,\n          170,   86,  170,  170,   89,   90,   91,  170,   93,  170,\n           95,  129,   97,  170,  170,  100,  170,  170,  170,  170,\n          105,  106,  107,  171,  173,  172,  111,  112,   -1,   32,\n           -1,    1,  117,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           76,   -1,   -1,   -1,  129,   -1,   -1,  165,   -1,   -1,\n           86,  169,   -1,   89,   90,   91,   -1,   93,   -1,   95,\n            1,   97,   -1,   -1,  100,   -1,   -1,   -1,   -1,  105,\n          106,  107,   -1,   76,   -1,  111,  112,   -1,   -1,   -1,\n          165,  117,   -1,   86,  169,   -1,   89,   90,   91,   -1,\n           93,   -1,   95,  129,   97,   -1,   -1,  100,   -1,   -1,\n           -1,   -1,  105,  106,  107,   -1,   76,   -1,  111,  112,\n           -1,   -1,   72,   73,  117,   -1,   86,   -1,   -1,   89,\n           90,   91,   -1,   93,   84,   95,  129,   97,   88,  165,\n          100,   -1,   -1,  169,    1,  105,  106,  107,   -1,   -1,\n           -1,  111,  112,   84,   72,   73,   -1,  117,   -1,   -1,\n           -1,   31,   -1,   -1,   -1,   -1,   84,   -1,   -1,  129,\n           88,   -1,  165,   -1,  124,   -1,  169,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  119,  120,\n           -1,   -1,  142,  124,  144,  145,  146,  147,  148,  149,\n          150,   -1,  133,   -1,   -1,  165,  124,  157,  158,  169,\n           -1,  142,   82,   -1,   -1,   -1,   -1,  167,   -1,   -1,\n           -1,   -1,  172,  173,  142,   -1,  144,  145,  146,  147,\n          148,  149,  150,  164,   -1,   -1,  167,   -1,   -1,  157,\n          158,   -1,  173,   -1,   -1,   -1,  103,   -1,  118,  167,\n           -1,  108,   -1,  110,  172,  173,   -1,   -1,  115,   -1,\n           -1,  118,  119,  120,  121,  122,  123,  124,  125,  126,\n          127,  128,  142,  143,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,  161,  162,  163,   -1,   -1,   -1,  167,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,  170\n    );\n\n    protected array $actionBase = array(\n            0,  156,   -3,  315,  474,  474,  887,  954, 1009, 1080,\n         1460,  227,  214,  -61, 1222, 1304, 1304, 1337, 1304, 1131,\n         1255,   74, 1370, 1370, 1370,  898,  824,  632,  632,  824,\n          632,  762,  762,  762,  762,  778,  778,  425,  425,   40,\n          422,  263,   54,  408,  408,  408,  408,  408,  597,  408,\n          408,  408,  408,  408,  597,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,  408,  408,  408,  408,\n          408,  408,  408,  408,  408,  408,   32,  116,  331,   25,\n         1133,  765, 1084, 1093, 1087, 1094, 1079, 1076, 1085, 1089,\n         1097, 1187, 1188,  853, 1186, 1189, 1090,  911, 1083, 1091,\n          893,  616,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,  616,  616,  616,   24,  174,\n           71,  484,  484,  484,  484,  484,  484,  484,  484,  484,\n          484,  484,  484,  484,  484,  484,  484,  484,  484,  484,\n          484,  458,  458,  458, 1122, 1122,  180,   20, 1412, 1380,\n         1412, 1412, 1412, 1412, 1412, 1412, 1412, 1412,  206,  188,\n          804,  171,  171,    6,    6,    6,    6,    6, 1473,   53,\n         1157,  310,  310,  310,  310, 1399, 1399,  -51,  506,  574,\n          348,  351,  673,  -96,  646,  349,  199,  641,  641,  419,\n          419,  640,  640,  419,  419,  419,  311,  311,  416,  416,\n          416,  416,  393,  157,  786,  200,  200,  200,  200,  786,\n          786,  786,  786,  820, 1193,  786,  970,  981,  786,  786,\n          232,  369,  391,  647,  647,  582,   -4,   -4,  582,  -95,\n           -4,  341,  443,   85,  791,  277,  527,   85,  992,  383,\n          402,  402,  541,  402,  402,  402,  808,  610,  808, 1072,\n          821,  821,  842,  805,  902, 1134, 1105,  815, 1183,  839,\n         1184, 1135,  178,  542,  211,  421,  460,  803, 1071, 1071,\n         1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071, 1071,\n         1191,  506, 1072,  365, 1177, 1179, 1191, 1191, 1191,  506,\n          506,  506,  506,  506,  506,  506,  506,  843,  506,  506,\n          672,  365,  625,  635,  365,  859,  506,  831,   32,   32,\n           32,   32,   32,   32,   32,   32,   32,   32,   32,  -17,\n           32,   32,  116,  516,  516,   32,  333,    5,  516,  516,\n          516,  366,  516,   32,   32,   32,  610,  828,  798,  663,\n           46,  799,  142,  828,  828,  828,   58,  173,  120,  783,\n          800,  578,  823,  823,  823,  827,  927,  927,  823,  826,\n          823,  827,  823,  823,  927,  927,  837,  927,  389,  639,\n          546,  620,  674,  927,  502,  823,  823,  823,  823,  790,\n          927,  128,  203,  680,  823,  497,  433,  823,  823,  790,\n          784,  849,  811,  927,  927,  927,  790,  605,  811,  811,\n          811,  860,  866,  810,  847,  530,  509,  690,  339,  864,\n          847,  847,  823,  624,  810,  847,  810,  847,  785,  847,\n          847,  847,  810,  847,  826,  592,  847,  795,  685,  306,\n          847,  823,   23,  938,  940,  774,  941,  934,  951,  988,\n          955,  958, 1114,  926,  968,  936,  960,  990,  930,  929,\n          852,  782,  787,  834,  771,  925,  818,  818,  818,  915,\n          917,  818,  818,  818,  818,  818,  818,  818,  818,  782,\n          776,  845,  832,  972,  792,  793, 1051,  777, 1136, 1192,\n          970,  938,  958,  788,  936,  960,  930,  929,  840,  836,\n          816,  835,  813,  809,  806,  807,  846,  963,  838,  794,\n         1004,  973, 1121, 1109,  979,  980, 1013, 1059,  867, 1061,\n         1137,  830, 1139, 1140,  904,  982, 1115,  818,  913,  901,\n          906,  981,  924,  782,  909, 1062, 1064,  996, 1106, 1022,\n         1025, 1113,  868,  829,  910, 1144,  983,  984,  985, 1116,\n         1117,  844,  997,  780, 1028,  869,  854, 1030, 1033, 1034,\n         1035, 1119, 1146, 1123,  912, 1124,  870,  817,  865,  814,\n         1148,  363,  857,  858,  863,  987,  591,  969, 1128, 1104,\n         1150, 1037, 1040, 1043, 1153, 1155,  964,  871,  999,  819,\n         1000,  994,  872,  873,  607,  862, 1065,  855,  856,  861,\n          626,  689, 1156, 1162, 1165,  967,  850,  825,  874,  876,\n         1066,  848, 1067, 1167,  705,  877, 1170, 1057,  796,  797,\n          608,  781,  770,  801,  822, 1132,  841,  802,  833,  986,\n          797,  851,  881, 1172,  883,  885,  888, 1050,  890, 1008,\n         1173,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  632,  632,  632,  632,  789,  789,\n          789,  789,  789,  789,  789,  632,  789,  789,  789,  632,\n          632,    0,    0,  632,    0,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          789,  789,  789,  789,  789,  789,  789,  789,  789,  789,\n          616,  616,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,  616,  616,  616,  616,  616,\n          616,  616,  616,  616,  616,  616,  616,  616,  358,  358,\n          616,  616,  358,  358,  358,  358,  358,  358,  358,  358,\n          358,  358,  616,  616,    0,  616,  616,  616,  616,  616,\n          616,  616,  837,  358,  358,  311,  311,  311,  311,  358,\n          358,  212,  212,  212,  358,  311,  358,  -95,  311,  358,\n          -95,  358,  358,  358,  358,  358,  358,  358,  358,  358,\n            0,    0,  358,  358,  358,  358,  365,   -4,  358,  826,\n          826,  826,  826,  358,  358,  358,  358,   -4,   -4,  358,\n          -55,  -55,  358,  358,    0,    0,    0,  311,  311,  365,\n            0,    0,  365,    0,    0,  826,  826,  358,  -95,  837,\n          343,  358,  178,    0,    0,    0,    0,    0,    0,    0,\n          365,  826,  365,  506,   -4,   -4,  506,  506,  516,   32,\n          343,  613,  613,  613,  613,   32,    0,    0,    0,    0,\n            0,  610,  837,  837,  837,  837,  837,  837,  837,  837,\n          837,  837,  837,  837,  826,    0,  837,    0,  837,  837,\n          826,  826,  826,    0,    0,    0,    0,    0,    0,    0,\n            0,  927,    0,    0,    0,    0,    0,    0,    0,  826,\n            0,  927,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,  826,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,  818,  868,    0,    0,  868,    0,  818,  818,  818,\n            0,    0,    0,  862,  848\n    );\n\n    protected array $actionDefault = array(\n            3,32767,32767,32767,  102,  102,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,  100,\n        32767,  632,  632,  632,  632,32767,32767,  257,  102,32767,\n        32767,  503,32767,  417,  417,  417,32767,32767,32767,  576,\n          576,  576,  576,  576,   17,32767,32767,32767,32767,32767,\n        32767,32767,  503,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,   36,    7,    8,   10,   11,   49,  340,\n          100,32767,32767,32767,32767,32767,32767,32767,  102,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n          404,  625,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  497,  507,  485,  486,  488,  489,  416,  577,  631,\n          344,  628,  339,  415,  146,  354,  342,  245,  261,  508,\n          262,  509,  512,  513,  218,  401,  150,  151,  448,  504,\n          450,  502,  506,  449,  422,  429,  430,  431,  432,  433,\n          434,  435,  436,  437,  438,  439,  440,  441,  420,  421,\n          505,  482,  481,  480,32767,32767,  446,  447,32767,32767,\n        32767,32767,32767,32767,32767,32767,  102,32767,  451,  454,\n          419,  452,  453,  470,  471,  468,  469,  472,32767,  323,\n        32767,  473,  474,  475,  476,32767,32767,  382,  196,  380,\n        32767,  477,32767,  111,  455,  323,  111,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,  461,  462,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,  102,32767,32767,32767,  100,\n          520,  570,  479,  456,  457,32767,  545,32767,  102,32767,\n          547,32767,32767,32767,32767,32767,32767,32767,32767,  572,\n          443,  445,  540,  626,  423,  629,32767,  533,  100,  196,\n        32767,  546,  196,  196,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,  571,32767,  639,  533,  110,  110,\n          110,  110,  110,  110,  110,  110,  110,  110,  110,  110,\n        32767,  196,  110,32767,  110,  110,32767,32767,  100,  196,\n          196,  196,  196,  196,  196,  196,  196,  548,  196,  196,\n          191,32767,  271,  273,  102,  594,  196,  550,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  404,32767,32767,32767,32767,  533,  466,  139,32767,\n          535,  139,  578,  458,  459,  460,  578,  578,  578,  319,\n          296,32767,32767,32767,32767,32767,  548,  548,  100,  100,\n          100,  100,32767,32767,32767,32767,  111,  519,   99,   99,\n           99,   99,   99,  103,  101,32767,32767,32767,32767,  226,\n        32767,  101,  101,   99,32767,  101,  101,32767,32767,  226,\n          228,  215,  230,32767,  598,  599,  226,  101,  230,  230,\n          230,  250,  250,  522,  325,  101,   99,  101,  101,  198,\n          325,  325,32767,  101,  522,  325,  522,  325,  200,  325,\n          325,  325,  522,  325,32767,  101,  325,  217,   99,   99,\n          325,32767,32767,32767,32767,  535,32767,32767,32767,32767,\n        32767,32767,32767,  225,32767,32767,32767,32767,32767,32767,\n        32767,32767,  565,32767,  583,  596,  464,  465,  467,  582,\n          580,  490,  491,  492,  493,  494,  495,  496,  499,  627,\n        32767,  539,32767,32767,32767,  353,32767,  637,32767,32767,\n        32767,    9,   74,  528,   42,   43,   51,   57,  554,  555,\n          556,  557,  551,  552,  558,  553,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n          638,32767,  578,32767,32767,32767,32767,  463,  560,  604,\n        32767,32767,  579,  630,32767,32767,32767,32767,32767,32767,\n        32767,32767,  139,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,  565,32767,  137,32767,32767,32767,32767,\n        32767,32767,32767,32767,  561,32767,32767,32767,  578,32767,\n        32767,32767,32767,  321,  318,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  578,32767,32767,32767,32767,32767,  298,32767,  315,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,  400,  535,\n          301,  303,  304,32767,32767,32767,32767,  376,32767,32767,\n        32767,32767,32767,32767,32767,32767,32767,32767,32767,32767,\n        32767,  153,  153,    3,    3,  356,  153,  153,  153,  356,\n          356,  153,  356,  356,  356,  153,  153,  153,  153,  153,\n          153,  153,  283,  186,  265,  268,  250,  250,  153,  368,\n          153,  402,  402,  411\n    );\n\n    protected array $goto = array(\n          200,  168,  200,  200,  200, 1066, 1098,  716,  447,  681,\n          641,  678,  442,  344,  340,  341,  343,  612,  446,  345,\n          448,  658,  480,  725,  569,  569,  569,  569, 1242,  623,\n          171,  171,  171,  171,  224,  201,  197,  197,  181,  183,\n          219,  206,  197,  197,  197,  197,  197, 1192,  198,  198,\n          198,  198,  198, 1192,  191,  192,  193,  194,  195,  196,\n          221,  219,  222,  556,  557,  437,  558,  561,  562,  563,\n          564,  565,  566,  567,  568,  172,  173,  174,  199,  175,\n          176,  177,  169,  178,  179,  180,  182,  218,  220,  223,\n          241,  246,  247,  258,  259,  261,  262,  263,  264,  265,\n          266,  267,  271,  272,  273,  274,  281,  284,  296,  297,\n          323,  324,  443,  444,  445,  617,  225,  226,  227,  228,\n          229,  230,  231,  232,  233,  234,  235,  236,  237,  238,\n          239,  240,  192,  193,  194,  195,  196,  221,  202,  203,\n          204,  205,  242,  184,  185,  186,  207,  203,  187,  243,\n          167,  208,  209,  188,  210,  211,  212,  189,  213,  214,\n          170,  215,  216,  217,  190,  880,  286,  283,  286,  286,\n          877, 1122,  254,  254,  254,  254,  254,  602,  358,  878,\n          619,  755,  657,  659, 1003,  441,  679,  632,  858,  852,\n          703,  706, 1038,  714,  723, 1034,  730,  919,  876,  919,\n          919,  435,  252,  252,  252,  252,  249,  255, 1069, 1069,\n          701,  980, 1397, 1397, 1061, 1077, 1078,  350,  935,  930,\n          931,  944,  886,  932,  883,  933,  934,  884,  887, 1397,\n          938,  891,  858,  912,  858,  890,  356, 1041, 1041,  873,\n          351,  350,  873, 1128, 1124, 1125,  531,  643,  643, 1400,\n         1400, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329, 1329,\n         1329,  609,  618, 1141, 1066, 1298,  410,  413,  620,  624,\n         1298, 1298, 1097, 1099, 1101, 1066,  728, 1298,  527,  719,\n         1066, 1139, 1066, 1066, 1066, 1066, 1066, 1066, 1066, 1066,\n         1066,  873,  713, 1066, 1066, 1066, 1066,  674,  675, 1298,\n          692,  693,  694,  854, 1298, 1298, 1298, 1298,  713,  475,\n         1298,  713,  475, 1298, 1298, 1379, 1379, 1379, 1379, 1387,\n          580,  573, 1072, 1071,  894,  366,  968,  968,  952, 1148,\n         1176, 1149,  953,  486,  486,  366,  366,  363,  363,  363,\n          363,  571,  906,  486,  498,  893,  571,  571,  366,  366,\n         1024,  500,  366,  571, 1414,  457,  408,  316,  573,  580,\n          604,  605,  317,  615,  621,  607,  637,  638,  519,  575,\n          520,  680,  366,  366,   28,  473,  526,  995,  426,  724,\n          997,  997,  997,  997, 1075, 1076,  473, 1348, 1348,  991,\n          998, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348, 1348,\n         1348, 1345, 1345,  330,  314, 1345, 1345, 1345, 1345, 1345,\n         1345, 1345, 1345, 1345, 1345,  257,  257,  495, 1372, 1373,\n         1374, 1375,  873,  907,  895, 1110, 1114, 1359,  466,  939,\n          466,  940,  359,  360, 1188,  466,  466, 1006, 1090, 1370,\n          651,  653,  655,  702, 1370, 1370,  559,  559,  686,  431,\n          559, 1370,  559,  559,  559,  559,  559,  559,  559,  559,\n          996,  346,  574,  599,  574,    8,  455,    9,  574,  636,\n          599,  870,  411,  479, 1381, 1381, 1381, 1381,  613,  635,\n          986,  575, 1160,  911,  417,  489,  616,  490,  491,  899,\n          896, 1171, 1046, 1289,  904, 1111,  758, 1405, 1406, 1057,\n         1366,  560,  560,  418,  496,  560,  560,  560,  560,  560,\n          560,  560,  560,  560,  560, 1027,  908, 1008,  999, 1115,\n          754,  385,  902,  572, 1036, 1031, 1162,    0,  466,  466,\n          466,  466,  466,  466,  466,  466,  466,  466,  466,  466,\n            0,  338,  466,    0,  466,  466, 1291,    0,    0, 1113,\n            0, 1293,    0,    0,    0, 1368, 1368, 1113,  630,  644,\n          647,  648,  649,  650,  671,  672,  673,  727,  729,    0,\n          625,  626,  423,  424,  957, 1178,    0,  690,    0,  691,\n            0,  428,  429,  430,    0,  704, 1043,    0,  432,    0,\n            0,    0,  354,    0,  898,    0,  684, 1022,    0,  277,\n            0,  329,  892,  449,    0,    0,  329,  329, 1294, 1295,\n            0, 1281,    0,    0, 1288,    0,    0,  868,    0,  449,\n            0,    0, 1274,  972, 1281, 1073, 1073, 1275, 1278,  973,\n            0, 1279,  685, 1084, 1080, 1081,    0, 1296, 1356, 1357,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,    0,    0,    0,    0,    0,\n            0,    0,    0,    0,    0,  763,  763\n    );\n\n    protected array $gotoCheck = array(\n           42,   42,   42,   42,   42,   73,  130,   73,   66,   66,\n           56,   56,   66,   66,   66,   66,   66,   66,   66,   66,\n           66,   66,  158,    9,  107,  107,  107,  107,  158,  107,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   15,   23,   23,   23,   23,\n           26,   15,    5,    5,    5,    5,    5,   48,   97,   27,\n          133,   48,   48,   48,   49,   13,   48,   13,   12,    6,\n           48,   48,   48,   48,   48,   48,   48,   25,   25,   25,\n           25,   43,    5,    5,    5,    5,    5,    5,   89,   89,\n           89,   89,  190,  190,   89,   89,   89,  176,   15,   15,\n           15,   15,   15,   15,   15,   15,   15,   15,   15,  190,\n           15,   15,   12,   45,   12,   15,  187,  107,  107,   22,\n          176,  176,   22,   15,   15,   15,   76,  108,  108,  190,\n          190,  108,  108,  108,  108,  108,  108,  108,  108,  108,\n          108,  180,    8,    8,   73,   73,   59,   59,   59,   59,\n           73,   73,  129,  129,  129,   73,    8,   73,    8,    8,\n           73,    8,   73,   73,   73,   73,   73,   73,   73,   73,\n           73,   22,    7,   73,   73,   73,   73,   86,   86,   73,\n           86,   86,   86,    7,   73,   73,   73,   73,    7,   83,\n           73,    7,   83,   73,   73,    9,    9,    9,    9,  189,\n           76,   76,  119,  119,   35,   14,    9,    9,   73,  148,\n          148,  148,   73,  156,  156,   14,   14,   24,   24,   24,\n           24,   19,   35,  156,   84,   35,   19,   19,   14,   14,\n          103,   84,   14,   19,   14,   83,   62,   76,   76,   76,\n           76,   76,   76,   76,   76,  104,   76,   76,  162,   14,\n          162,   64,   14,   14,   76,   19,  162,   93,   93,   93,\n           19,   19,   19,   19,  120,  120,   19,  178,  178,   19,\n           19,  178,  178,  178,  178,  178,  178,  178,  178,  178,\n          178,  179,  179,  177,  177,  179,  179,  179,  179,  179,\n          179,  179,  179,  179,  179,    5,    5,  184,  184,  184,\n          186,  186,   22,   16,   16,   16,   16,   14,   23,   65,\n           23,   65,   97,   97,  157,   23,   23,   16,  115,  133,\n           85,   85,   85,  117,  133,  133,  164,  164,  121,   14,\n          164,  133,  164,  164,  164,  164,  164,  164,  164,  164,\n           16,   29,    9,    9,    9,   46,  113,   46,    9,   80,\n            9,   18,    9,    9,  133,  133,  133,  133,    2,    2,\n           92,   14,   16,   16,   28,    9,    9,    9,    9,   39,\n           37,  155,  110,  168,    9,  132,   99,    9,    9,  114,\n          133,  181,  181,   31,  159,  181,  181,  181,  181,  181,\n          181,  181,  181,  181,  181,   50,   41,   96,   50,  135,\n           50,  140,    9,   50,   50,   50,  151,   -1,   23,   23,\n           23,   23,   23,   23,   23,   23,   23,   23,   23,   23,\n           -1,    9,   23,   -1,   23,   23,   14,   -1,   -1,  133,\n           -1,   20,   -1,   -1,   -1,  133,  133,  133,   81,   81,\n           81,   81,   81,   81,   81,   81,   81,   81,   81,   -1,\n           17,   17,   82,   82,   17,   17,   -1,   82,   -1,   82,\n           -1,   82,   82,   82,   -1,   82,   17,   -1,   82,   -1,\n           -1,   -1,   82,   -1,   17,   -1,   17,   17,   -1,   24,\n           -1,   24,   17,  118,   -1,   -1,   24,   24,   20,   20,\n           -1,   20,   -1,   -1,   17,   -1,   -1,   20,   -1,  118,\n           -1,   -1,   79,   79,   20,  118,  118,   79,   79,   79,\n           -1,   79,  118,  118,  118,  118,   -1,   20,   20,   20,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,\n           -1,   -1,   -1,   -1,   -1,   24,   24\n    );\n\n    protected array $gotoBase = array(\n            0,    0, -255,    0,    0,  171,  176,  282,  251,   10,\n            0,    0, -114, -161,   22, -190,  -46,   89,  156,   71,\n          144,    0,  -44,  160,  331,  191,  163,  172,  138,  159,\n            0,   49,    0,    0,    0,  -59,    0,  142,    0,  161,\n            0,   58,   -1,  175,    0,  204, -293,    0, -555,  164,\n          501,    0,    0,    0,    0,    0,  -34,    0,    0,  216,\n            0,    0,  310,    0,  126,  413, -236,    0,    0,    0,\n            0,    0,    0,   -5,    0,    0,  -32,    0,    0,  199,\n          152,  189,   62,   26, -145,  -58, -442,    0,    0,  -79,\n            0,    0,  146,   67,    0,    0,   57, -324,    0,   74,\n            0,    0,    0,  312,  318,    0,    0,   -7,    3,    0,\n          110,    0,    0,  181,   68,  158,    0,  154,  334,   35,\n           93,  150,    0,    0,    0,    0,    0,    0,    0,  269,\n            4,    0,  107,  169,    0,   60,    0,    0,    0,    0,\n         -241,    0,    0,    0,    0,    0,    0,    0,   52,    0,\n            0,   65,    0,    0,    0,  129,  296,  185, -254,   47,\n            0,    0, -146,    0,  202,    0,    0,    0,  112,    0,\n            0,    0,    0,    0,    0,    0,  -86,   77,  143,  157,\n          229,  257,    0,    0,  111,    0,   34,  203,    0,  285,\n         -101,    0,    0\n    );\n\n    protected array $gotoDefault = array(\n        -32768,  532,  765,    7,  766,  961,  841,  850,  596,  550,\n          726,  355,  645,  438, 1364,  937, 1177,  614,  869, 1307,\n         1313,  474,  872,  335,  752,  949,  920,  921,  414,  401,\n          885,  412,  669,  646,  513,  905,  470,  897,  505,  900,\n          469,  909,  166,  434,  529,  913,    6,  916,  578,  947,\n         1001,  402,  924,  403,  697,  926,  598,  928,  929,  409,\n          415,  416, 1182,  606,  642,  941,  260,  600,  942,  400,\n          943,  951,  405,  407,  707,  485,  524,  518,  427, 1143,\n          601,  629,  666,  463,  492,  640,  652,  639,  499,  450,\n          433,  334,  985,  993,  506,  483, 1007,  357, 1015,  760,\n         1190,  660,  508, 1023,  661, 1030, 1033,  551,  552,  497,\n         1045,  269, 1048,  509, 1058,   26,  687, 1063, 1064,  688,\n          662, 1086,  663,  689,  664, 1088,  482, 1191,  481, 1100,\n         1109,  471, 1112, 1353,  472, 1116,  268, 1119,  285,  361,\n          384,  451, 1126, 1127,   12, 1133,  717,  718,   25,  279,\n          528, 1161,  708, 1167,  278, 1170,  468, 1189,  467, 1262,\n         1264,  579,  510, 1282,  320, 1285,  700,  525, 1290,  464,\n         1355,  465,  553,  493,  342,  554, 1398,  313,  364,  339,\n          570,  321,  365,  555,  494, 1361, 1369,  336,   34, 1388,\n         1399,  611,  634\n    );\n\n    protected array $ruleToNonTerminal = array(\n            0,    1,    3,    3,    2,    5,    5,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    6,    6,    6,\n            6,    6,    6,    6,    6,    6,    6,    7,    7,    7,\n            7,    7,    7,    7,    7,    8,    8,    9,   10,   11,\n           11,   11,   12,   12,   13,   13,   14,   15,   15,   16,\n           16,   17,   17,   18,   18,   21,   21,   22,   23,   23,\n           24,   24,    4,    4,    4,    4,    4,    4,    4,    4,\n            4,    4,    4,    4,   29,   29,   30,   30,   32,   34,\n           34,   28,   36,   36,   33,   38,   38,   35,   35,   37,\n           37,   39,   39,   31,   40,   40,   41,   43,   44,   44,\n           45,   45,   46,   46,   48,   47,   47,   47,   47,   49,\n           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,\n           49,   49,   49,   49,   49,   49,   49,   49,   49,   49,\n           49,   49,   49,   25,   25,   50,   69,   69,   72,   72,\n           71,   70,   70,   63,   75,   75,   76,   76,   77,   77,\n           78,   78,   79,   79,   80,   80,   80,   80,   26,   26,\n           27,   27,   27,   27,   27,   88,   88,   90,   90,   83,\n           83,   91,   91,   92,   92,   92,   84,   84,   87,   87,\n           85,   85,   93,   94,   94,   57,   57,   65,   65,   68,\n           68,   68,   67,   95,   95,   96,   58,   58,   58,   58,\n           97,   97,   98,   98,   99,   99,  100,  101,  101,  102,\n          102,  103,  103,   55,   55,   51,   51,  105,   53,   53,\n          106,   52,   52,   54,   54,   64,   64,   64,   64,   81,\n           81,  109,  109,  111,  111,  112,  112,  112,  112,  112,\n          112,  112,  112,  110,  110,  110,  115,  115,  115,  115,\n           89,   89,  118,  118,  118,  119,  119,  116,  116,  120,\n          120,  122,  122,  123,  123,  117,  124,  124,  121,  125,\n          125,  125,  125,  113,  113,   82,   82,   82,   20,   20,\n          127,  127,  127,  128,  128,  128,  126,  126,  130,  130,\n          130,  130,  130,  130,  129,  129,   60,  131,  131,  132,\n           61,  134,  134,  135,  135,  136,  136,   86,  137,  137,\n          137,  137,  137,  137,  137,  137,  143,  143,  144,  144,\n          145,  145,  145,  145,  145,  146,  147,  147,  142,  142,\n          138,  138,  141,  141,  149,  149,  148,  148,  148,  148,\n          148,  148,  148,  148,  148,  148,  139,  150,  150,  152,\n          151,  151,  140,  140,  114,  114,  153,  153,  155,  155,\n          155,  154,  154,   62,  104,  156,  156,   56,   56,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,   42,   42,   42,   42,\n           42,   42,   42,   42,   42,   42,  163,  164,  164,  165,\n          157,  157,  162,  162,  166,  167,  167,  168,  169,  170,\n          170,  170,  170,   19,   19,   73,   73,   73,   73,  158,\n          158,  158,  158,  172,  172,  161,  161,  161,  159,  159,\n          178,  178,  178,  178,  178,  178,  178,  178,  178,  178,\n          179,  179,  179,  108,  181,  181,  181,  181,  160,  160,\n          160,  160,  160,  160,  160,  160,   59,   59,  175,  175,\n          175,  175,  175,  182,  182,  171,  171,  171,  171,  183,\n          183,  183,  183,  183,   74,   74,   66,   66,   66,   66,\n          133,  133,  133,  133,  186,  185,  174,  174,  174,  174,\n          174,  174,  173,  173,  173,  184,  184,  184,  184,  107,\n          180,  188,  188,  187,  187,  189,  189,  189,  189,  189,\n          189,  189,  189,  177,  177,  177,  177,  176,  191,  190,\n          190,  190,  190,  190,  190,  190,  190,  192,  192,  192,\n          192\n    );\n\n    protected array $ruleToLength = array(\n            1,    1,    2,    0,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    0,\n            1,    0,    1,    1,    2,    1,    3,    4,    1,    2,\n            0,    1,    1,    1,    1,    4,    3,    5,    4,    3,\n            4,    1,    3,    4,    1,    1,    8,    7,    2,    3,\n            1,    2,    3,    1,    2,    3,    1,    1,    3,    1,\n            3,    1,    2,    2,    3,    1,    3,    2,    3,    1,\n            3,    3,    2,    0,    1,    1,    1,    1,    1,    3,\n            7,   10,    5,    7,    9,    5,    3,    3,    3,    3,\n            3,    3,    1,    2,    5,    7,    9,    6,    5,    6,\n            3,    2,    1,    1,    1,    1,    0,    2,    1,    3,\n            8,    0,    4,    2,    1,    3,    0,    1,    0,    1,\n            0,    1,    3,    1,    1,    1,    1,    1,    8,    9,\n            7,    8,    7,    6,    8,    0,    2,    0,    2,    1,\n            2,    1,    2,    1,    1,    1,    0,    2,    0,    2,\n            0,    2,    2,    1,    3,    1,    4,    1,    4,    1,\n            1,    4,    2,    1,    3,    3,    3,    4,    4,    5,\n            0,    2,    4,    3,    1,    1,    7,    0,    2,    1,\n            3,    3,    4,    1,    4,    0,    2,    5,    0,    2,\n            6,    0,    2,    0,    3,    1,    2,    1,    1,    2,\n            0,    1,    3,    0,    2,    1,    1,    1,    1,    1,\n            1,    1,    1,    7,    9,    6,    1,    2,    1,    1,\n            1,    1,    1,    1,    1,    1,    3,    3,    3,    1,\n            3,    3,    3,    3,    3,    1,    3,    3,    1,    1,\n            2,    1,    1,    0,    1,    0,    2,    2,    2,    4,\n            2,    4,    4,    3,    1,    3,    1,    3,    2,    2,\n            1,    1,    3,    3,    1,    1,    2,    3,    1,    1,\n            2,    3,    1,    1,    3,    2,    0,    1,    5,    7,\n            5,    6,   10,    3,    5,    1,    1,    3,    0,    2,\n            4,    5,    4,    4,    4,    3,    1,    1,    1,    1,\n            1,    1,    0,    1,    1,    2,    1,    1,    1,    1,\n            1,    1,    1,    1,    1,    1,    2,    1,    3,    1,\n            1,    3,    0,    2,    0,    3,    5,    8,    1,    3,\n            3,    0,    2,    2,    2,    3,    1,    0,    1,    1,\n            3,    3,    3,    4,    4,    1,    1,    2,    2,    3,\n            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,\n            3,    3,    2,    2,    2,    2,    3,    3,    3,    3,\n            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,\n            3,    3,    3,    3,    2,    2,    2,    2,    3,    3,\n            3,    3,    3,    3,    3,    3,    3,    3,    3,    3,\n            5,    4,    3,    4,    4,    2,    2,    4,    2,    2,\n            2,    2,    2,    2,    2,    2,    2,    2,    2,    2,\n            1,    3,    2,    1,    2,    4,    2,    2,    8,    9,\n            8,    9,    9,   10,    9,   10,    8,    3,    2,    2,\n            1,    1,    0,    4,    2,    1,    3,    2,    1,    2,\n            2,    2,    4,    1,    1,    1,    1,    1,    1,    1,\n            1,    3,    1,    1,    1,    0,    1,    1,    0,    1,\n            1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\n            3,    5,    3,    3,    4,    1,    1,    3,    1,    1,\n            1,    1,    1,    3,    2,    3,    0,    1,    1,    3,\n            1,    1,    1,    1,    1,    1,    3,    1,    1,    1,\n            4,    1,    4,    4,    0,    1,    1,    1,    3,    3,\n            1,    4,    2,    2,    1,    3,    1,    4,    3,    3,\n            3,    3,    1,    3,    1,    1,    3,    1,    1,    4,\n            1,    1,    1,    3,    1,    1,    2,    1,    3,    4,\n            3,    2,    0,    2,    2,    1,    2,    1,    1,    1,\n            4,    3,    3,    3,    3,    6,    3,    1,    1,    2,\n            1\n    );\n\n    protected function initReduceCallbacks(): void {\n        $this->reduceCallbacks = [\n            0 => null,\n            1 => static function ($self, $stackPos) {\n                 $self->semValue = $self->handleNamespaces($self->semStack[$stackPos-(1-1)]);\n            },\n            2 => static function ($self, $stackPos) {\n                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;\n            },\n            3 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            4 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            5 => null,\n            6 => null,\n            7 => null,\n            8 => null,\n            9 => null,\n            10 => null,\n            11 => null,\n            12 => null,\n            13 => null,\n            14 => null,\n            15 => null,\n            16 => null,\n            17 => null,\n            18 => null,\n            19 => null,\n            20 => null,\n            21 => null,\n            22 => null,\n            23 => null,\n            24 => null,\n            25 => null,\n            26 => null,\n            27 => null,\n            28 => null,\n            29 => null,\n            30 => null,\n            31 => null,\n            32 => null,\n            33 => null,\n            34 => null,\n            35 => null,\n            36 => null,\n            37 => null,\n            38 => null,\n            39 => null,\n            40 => null,\n            41 => null,\n            42 => null,\n            43 => null,\n            44 => null,\n            45 => null,\n            46 => null,\n            47 => null,\n            48 => null,\n            49 => null,\n            50 => null,\n            51 => null,\n            52 => null,\n            53 => null,\n            54 => null,\n            55 => null,\n            56 => null,\n            57 => null,\n            58 => null,\n            59 => null,\n            60 => null,\n            61 => null,\n            62 => null,\n            63 => null,\n            64 => null,\n            65 => null,\n            66 => null,\n            67 => null,\n            68 => null,\n            69 => null,\n            70 => null,\n            71 => null,\n            72 => null,\n            73 => null,\n            74 => null,\n            75 => null,\n            76 => static function ($self, $stackPos) {\n                 $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])));\n            },\n            77 => null,\n            78 => null,\n            79 => null,\n            80 => null,\n            81 => null,\n            82 => null,\n            83 => null,\n            84 => null,\n            85 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            86 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            87 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            88 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            89 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            90 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            91 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            92 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            93 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            94 => null,\n            95 => static function ($self, $stackPos) {\n                 $self->semValue = new Name(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            96 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            97 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            98 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            99 => static function ($self, $stackPos) {\n                 /* nothing */\n            },\n            100 => static function ($self, $stackPos) {\n                 $self->emitError(new Error('A trailing comma is not allowed here', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])));\n            },\n            101 => null,\n            102 => null,\n            103 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Attribute($self->semStack[$stackPos-(1-1)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            104 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            105 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            106 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            107 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\AttributeGroup($self->semStack[$stackPos-(4-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            108 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            109 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            110 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            111 => null,\n            112 => null,\n            113 => null,\n            114 => null,\n            115 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\HaltCompiler($self->handleHaltCompiler(), $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            116 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Namespace_($self->semStack[$stackPos-(3-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_SEMICOLON);\n            $self->checkNamespace($self->semValue);\n            },\n            117 => static function ($self, $stackPos) {\n                 $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]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_BRACED);\n            $self->checkNamespace($self->semValue);\n            },\n            118 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Namespace_(null, $self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            $self->semValue->setAttribute('kind', Stmt\\Namespace_::KIND_BRACED);\n            $self->checkNamespace($self->semValue);\n            },\n            119 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Use_($self->semStack[$stackPos-(3-2)], Stmt\\Use_::TYPE_NORMAL, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            120 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            121 => null,\n            122 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Const_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]), []);\n            },\n            123 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Const_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(4-1)]);\n            $self->checkConstantAttributes($self->semValue);\n            },\n            124 => static function ($self, $stackPos) {\n                 $self->semValue = Stmt\\Use_::TYPE_FUNCTION;\n            },\n            125 => static function ($self, $stackPos) {\n                 $self->semValue = Stmt\\Use_::TYPE_CONSTANT;\n            },\n            126 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\GroupUse($self->semStack[$stackPos-(8-3)], $self->semStack[$stackPos-(8-6)], $self->semStack[$stackPos-(8-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));\n            },\n            127 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\GroupUse($self->semStack[$stackPos-(7-2)], $self->semStack[$stackPos-(7-5)], Stmt\\Use_::TYPE_UNKNOWN, $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]));\n            },\n            128 => null,\n            129 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            130 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            131 => null,\n            132 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            133 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            134 => null,\n            135 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            136 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            137 => static function ($self, $stackPos) {\n                 $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));\n            },\n            138 => static function ($self, $stackPos) {\n                 $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));\n            },\n            139 => static function ($self, $stackPos) {\n                 $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));\n            },\n            140 => static function ($self, $stackPos) {\n                 $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));\n            },\n            141 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->semValue->type = Stmt\\Use_::TYPE_NORMAL;\n            },\n            142 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)]; $self->semValue->type = $self->semStack[$stackPos-(2-1)];\n            },\n            143 => null,\n            144 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            145 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            146 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            147 => null,\n            148 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            149 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            150 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            151 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            152 => static function ($self, $stackPos) {\n                 if ($self->semStack[$stackPos-(2-2)] !== null) { $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; } $self->semValue = $self->semStack[$stackPos-(2-1)];;\n            },\n            153 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            154 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            155 => null,\n            156 => null,\n            157 => null,\n            158 => static function ($self, $stackPos) {\n                 throw new Error('__HALT_COMPILER() can only be used from the outermost scope', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            159 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Block($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            160 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            161 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            162 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            163 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            164 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            165 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            166 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Break_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            167 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Continue_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            168 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Return_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            169 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Global_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            170 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Static_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            171 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Echo_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            172 => static function ($self, $stackPos) {\n\n        $self->semValue = new Stmt\\InlineHTML($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n        $self->semValue->setAttribute('hasLeadingNewline', $self->inlineHtmlHasLeadingNewline($stackPos-(1-1)));\n\n            },\n            173 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Expression($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            174 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Unset_($self->semStack[$stackPos-(5-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));\n            },\n            175 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            176 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            177 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            178 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            179 => static function ($self, $stackPos) {\n                 $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);\n            },\n            180 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Goto_($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            181 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Label($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            182 => static function ($self, $stackPos) {\n                 $self->semValue = null; /* means: no statement */\n            },\n            183 => null,\n            184 => static function ($self, $stackPos) {\n                 $self->semValue = $self->maybeCreateNop($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]);\n            },\n            185 => static function ($self, $stackPos) {\n                 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)]]; };\n            },\n            186 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            187 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            188 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            189 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            190 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            191 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            192 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Finally_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            193 => null,\n            194 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            195 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            196 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            197 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            198 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            199 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            200 => static function ($self, $stackPos) {\n                 $self->semValue = false;\n            },\n            201 => static function ($self, $stackPos) {\n                 $self->semValue = true;\n            },\n            202 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            203 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            204 => null,\n            205 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            206 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            207 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            208 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            209 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            210 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClass($self->semValue, $stackPos-(7-2));\n            },\n            211 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClass($self->semValue, $stackPos-(8-3));\n            },\n            212 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkInterface($self->semValue, $stackPos-(7-3));\n            },\n            213 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            214 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkEnum($self->semValue, $stackPos-(8-3));\n            },\n            215 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            216 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            217 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            218 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            219 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            220 => null,\n            221 => null,\n            222 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            223 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::ABSTRACT;\n            },\n            224 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            225 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            226 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            227 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            228 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            229 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            230 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            231 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            232 => null,\n            233 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            234 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            235 => null,\n            236 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            237 => null,\n            238 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            239 => static function ($self, $stackPos) {\n                 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)]]; };\n            },\n            240 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            241 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            242 => null,\n            243 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            244 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            245 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            246 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            247 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-3)];\n            },\n            248 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            249 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(5-3)];\n            },\n            250 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            251 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            252 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            253 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Case_(null, $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            254 => null,\n            255 => null,\n            256 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            257 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            258 => null,\n            259 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            260 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            261 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            262 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\MatchArm(null, $self->semStack[$stackPos-(4-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            263 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            264 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            265 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            266 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            267 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            268 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            269 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            270 => static function ($self, $stackPos) {\n                 $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);\n            },\n            271 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            272 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Else_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            273 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            274 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Else_($self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos])); $self->fixupAlternativeElse($self->semValue);\n            },\n            275 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);\n            },\n            276 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(2-2)], true);\n            },\n            277 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)], false);\n            },\n            278 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->fixupArrayDestructuring($self->semStack[$stackPos-(1-1)]), false);\n            },\n            279 => null,\n            280 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            281 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            282 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            283 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            284 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            285 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC;\n            },\n            286 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED;\n            },\n            287 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE;\n            },\n            288 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC_SET;\n            },\n            289 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED_SET;\n            },\n            290 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE_SET;\n            },\n            291 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            292 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            293 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Param($self->semStack[$stackPos-(7-6)], null, $self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-4)], $self->semStack[$stackPos-(7-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(7-2)], $self->semStack[$stackPos-(7-1)], $self->semStack[$stackPos-(7-7)]);\n            $self->checkParam($self->semValue);\n            $self->addPropertyNameToHooks($self->semValue);\n            },\n            294 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Param($self->semStack[$stackPos-(9-6)], $self->semStack[$stackPos-(9-8)], $self->semStack[$stackPos-(9-3)], $self->semStack[$stackPos-(9-4)], $self->semStack[$stackPos-(9-5)], $self->getAttributes($self->tokenStartStack[$stackPos-(9-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(9-2)], $self->semStack[$stackPos-(9-1)], $self->semStack[$stackPos-(9-9)]);\n            $self->checkParam($self->semValue);\n            $self->addPropertyNameToHooks($self->semValue);\n            },\n            295 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            296 => null,\n            297 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            298 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            299 => null,\n            300 => null,\n            301 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Name('static', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            302 => static function ($self, $stackPos) {\n                 $self->semValue = $self->handleBuiltinTypes($self->semStack[$stackPos-(1-1)]);\n            },\n            303 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier('array', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            304 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Identifier('callable', $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            305 => null,\n            306 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            307 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            308 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            309 => null,\n            310 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            311 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            312 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            313 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            314 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            315 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            316 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            317 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            318 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\IntersectionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            319 => null,\n            320 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\NullableType($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            321 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\UnionType($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            322 => null,\n            323 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            324 => null,\n            325 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            326 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(2-2)];\n            },\n            327 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            328 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            329 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            330 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            331 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-2)];\n            },\n            332 => static function ($self, $stackPos) {\n                 $self->semValue = array(new Node\\Arg($self->semStack[$stackPos-(4-2)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));\n            },\n            333 => static function ($self, $stackPos) {\n                 $self->semValue = array(new Node\\Arg($self->semStack[$stackPos-(3-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)],  $self->tokenEndStack[$stackPos-(3-1)])), $self->semStack[$stackPos-(3-3)]);\n            },\n            334 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            335 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            336 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            337 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            338 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(2-2)], true, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            339 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(2-2)], false, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            340 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\VariadicPlaceholder($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            341 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArgPlaceholder(null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            342 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            343 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArgPlaceholder($self->semStack[$stackPos-(3-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            344 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\Arg($self->semStack[$stackPos-(1-1)], false, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            345 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            346 => null,\n            347 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            348 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            349 => null,\n            350 => null,\n            351 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            352 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            353 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\StaticVar($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            354 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            355 => static function ($self, $stackPos) {\n                 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)]; }\n            },\n            356 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            357 => static function ($self, $stackPos) {\n                 $nop = $self->maybeCreateZeroLengthNop($self->tokenPos);;\n            if ($nop !== null) { $self->semStack[$stackPos-(1-1)][] = $nop; } $self->semValue = $self->semStack[$stackPos-(1-1)];\n            },\n            358 => static function ($self, $stackPos) {\n                 $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)]);\n            },\n            359 => static function ($self, $stackPos) {\n                 $self->semValue = new Stmt\\Property($self->semStack[$stackPos-(7-2)], $self->semStack[$stackPos-(7-4)], $self->getAttributes($self->tokenStartStack[$stackPos-(7-1)], $self->tokenEndStack[$stackPos]), $self->semStack[$stackPos-(7-3)], $self->semStack[$stackPos-(7-1)], $self->semStack[$stackPos-(7-6)]);\n            $self->checkPropertyHooksForMultiProperty($self->semValue, $stackPos-(7-5));\n            $self->checkEmptyPropertyHookList($self->semStack[$stackPos-(7-6)], $stackPos-(7-5));\n            $self->addPropertyNameToHooks($self->semValue);\n            },\n            360 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClassConst($self->semValue, $stackPos-(5-2));\n            },\n            361 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClassConst($self->semValue, $stackPos-(6-2));\n            },\n            362 => static function ($self, $stackPos) {\n                 $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]));\n            $self->checkClassMethod($self->semValue, $stackPos-(10-2));\n            },\n            363 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            364 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            365 => static function ($self, $stackPos) {\n                 $self->semValue = null; /* will be skipped */\n            },\n            366 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            367 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            368 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            369 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            370 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            371 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            372 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            373 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            374 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            375 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)]);\n            },\n            376 => null,\n            377 => static function ($self, $stackPos) {\n                 $self->semValue = array(null, $self->semStack[$stackPos-(1-1)]);\n            },\n            378 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            379 => null,\n            380 => null,\n            381 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            382 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            383 => null,\n            384 => null,\n            385 => static function ($self, $stackPos) {\n                 $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)];\n            },\n            386 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC;\n            },\n            387 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED;\n            },\n            388 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE;\n            },\n            389 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PUBLIC_SET;\n            },\n            390 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PROTECTED_SET;\n            },\n            391 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::PRIVATE_SET;\n            },\n            392 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::STATIC;\n            },\n            393 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::ABSTRACT;\n            },\n            394 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::FINAL;\n            },\n            395 => static function ($self, $stackPos) {\n                 $self->semValue = Modifiers::READONLY;\n            },\n            396 => null,\n            397 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            398 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            399 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\VarLikeIdentifier(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            400 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyItem($self->semStack[$stackPos-(1-1)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            401 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            402 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            403 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            404 => static function ($self, $stackPos) {\n                 $self->semValue = [];\n            },\n            405 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)]; $self->checkEmptyPropertyHookList($self->semStack[$stackPos-(3-2)], $stackPos-(3-1));\n            },\n            406 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyHook($self->semStack[$stackPos-(5-4)], $self->semStack[$stackPos-(5-5)], ['flags' => $self->semStack[$stackPos-(5-2)], 'byRef' => $self->semStack[$stackPos-(5-3)], 'params' => [], 'attrGroups' => $self->semStack[$stackPos-(5-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(5-1)], $self->tokenEndStack[$stackPos]));\n            $self->checkPropertyHook($self->semValue, null);\n            },\n            407 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\PropertyHook($self->semStack[$stackPos-(8-4)], $self->semStack[$stackPos-(8-8)], ['flags' => $self->semStack[$stackPos-(8-2)], 'byRef' => $self->semStack[$stackPos-(8-3)], 'params' => $self->semStack[$stackPos-(8-6)], 'attrGroups' => $self->semStack[$stackPos-(8-1)]], $self->getAttributes($self->tokenStartStack[$stackPos-(8-1)], $self->tokenEndStack[$stackPos]));\n            $self->checkPropertyHook($self->semValue, $stackPos-(8-5));\n            },\n            408 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            409 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            410 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            411 => static function ($self, $stackPos) {\n                 $self->semValue = 0;\n            },\n            412 => static function ($self, $stackPos) {\n                 $self->checkPropertyHookModifiers($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)];\n            },\n            413 => null,\n            414 => null,\n            415 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            416 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            417 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            418 => null,\n            419 => null,\n            420 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            421 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            422 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            423 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            424 => static function ($self, $stackPos) {\n                 $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]));\n            if (!$self->phpVersion->allowsAssignNewByReference()) {\n                $self->emitError(new Error('Cannot assign new by reference', $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos])));\n            }\n\n            },\n            425 => null,\n            426 => null,\n            427 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\FuncCall(new Node\\Name($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)],  $self->tokenEndStack[$stackPos-(2-1)])), $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            428 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Clone_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            429 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            430 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            431 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            432 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            433 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            434 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            435 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            436 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            437 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            438 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            439 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            440 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            441 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            442 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PostInc($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            443 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PreInc($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            444 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PostDec($self->semStack[$stackPos-(2-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            445 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\PreDec($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            446 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            447 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            448 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            449 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            450 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            451 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            452 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            453 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            454 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            455 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            456 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            457 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            458 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            459 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            460 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            461 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            462 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            463 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            464 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\UnaryPlus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            465 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\UnaryMinus($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            466 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\BooleanNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            467 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\BitwiseNot($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            468 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            469 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            470 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            471 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            472 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            473 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            474 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            475 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            476 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            477 => static function ($self, $stackPos) {\n\n          $self->semValue = new Expr\\BinaryOp\\Pipe($self->semStack[$stackPos-(3-1)], $self->semStack[$stackPos-(3-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n          $self->checkPipeOperatorParentheses($self->semStack[$stackPos-(3-3)]);\n\n            },\n            478 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            479 => static function ($self, $stackPos) {\n\n          $self->semValue = $self->semStack[$stackPos-(3-2)];\n          if ($self->semValue instanceof Expr\\ArrowFunction) {\n              $self->parenthesizedArrowFunctions->offsetSet($self->semValue);\n          }\n\n            },\n            480 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            481 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            482 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            483 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Isset_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            484 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Empty_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            485 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Include_($self->semStack[$stackPos-(2-2)], Expr\\Include_::TYPE_INCLUDE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            486 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            487 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Eval_($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            488 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Include_($self->semStack[$stackPos-(2-2)], Expr\\Include_::TYPE_REQUIRE, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            489 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            490 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getIntCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Int_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            491 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getFloatCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Double($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            492 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getStringCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\String_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            493 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Array_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            494 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Object_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            495 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]);\n            $attrs['kind'] = $self->getBoolCastKind($self->semStack[$stackPos-(2-1)]);\n            $self->semValue = new Expr\\Cast\\Bool_($self->semStack[$stackPos-(2-2)], $attrs);\n            },\n            496 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Unset_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            497 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Cast\\Void_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            498 => static function ($self, $stackPos) {\n                 $self->semValue = $self->createExitExpr($self->semStack[$stackPos-(2-1)], $stackPos-(2-1), $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            499 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ErrorSuppress($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            500 => null,\n            501 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ShellExec($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            502 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Print_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            503 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Yield_(null, null, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            504 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Yield_($self->semStack[$stackPos-(2-2)], null, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            505 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            506 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\YieldFrom($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            507 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Throw_($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            508 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            509 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            510 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            511 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            512 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            513 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            514 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            515 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            516 => static function ($self, $stackPos) {\n                 $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)]);\n            $self->checkClass($self->semValue[0], -1);\n            },\n            517 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            518 => static function ($self, $stackPos) {\n                 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]));\n            },\n            519 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\New_($self->semStack[$stackPos-(2-2)], [], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            520 => null,\n            521 => null,\n            522 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            523 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(4-3)];\n            },\n            524 => null,\n            525 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            526 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            527 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            528 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            529 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            530 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            531 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            532 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            533 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            534 => null,\n            535 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            536 => static function ($self, $stackPos) {\n                 $self->semValue = new Name($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            537 => static function ($self, $stackPos) {\n                 $self->semValue = new Name\\FullyQualified(substr($self->semStack[$stackPos-(1-1)], 1), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            538 => static function ($self, $stackPos) {\n                 $self->semValue = new Name\\Relative(substr($self->semStack[$stackPos-(1-1)], 10), $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            539 => null,\n            540 => null,\n            541 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            542 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;\n            },\n            543 => null,\n            544 => null,\n            545 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            546 => static function ($self, $stackPos) {\n                 $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()); } };\n            },\n            547 => static function ($self, $stackPos) {\n                 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)];\n            },\n            548 => static function ($self, $stackPos) {\n                 $self->semValue = array();\n            },\n            549 => null,\n            550 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\ConstFetch($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            551 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Line($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            552 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\File($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            553 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Dir($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            554 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Class_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            555 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Trait_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            556 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Method($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            557 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Function_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            558 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Namespace_($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            559 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\MagicConst\\Property($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            560 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            561 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            562 => static function ($self, $stackPos) {\n                 $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;\n            },\n            563 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\\Array_::KIND_SHORT;\n            $self->semValue = new Expr\\Array_($self->semStack[$stackPos-(3-2)], $attrs);\n            },\n            564 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Expr\\Array_::KIND_LONG;\n            $self->semValue = new Expr\\Array_($self->semStack[$stackPos-(4-3)], $attrs);\n            $self->createdArrays->offsetSet($self->semValue);\n            },\n            565 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $self->createdArrays->offsetSet($self->semValue);\n            },\n            566 => static function ($self, $stackPos) {\n                 $self->semValue = Scalar\\String_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->supportsUnicodeEscapes());\n            },\n            567 => static function ($self, $stackPos) {\n                 $attrs = $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]); $attrs['kind'] = Scalar\\String_::KIND_DOUBLE_QUOTED;\n            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);\n            },\n            568 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseLNumber($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]), $self->phpVersion->allowsInvalidOctals());\n            },\n            569 => static function ($self, $stackPos) {\n                 $self->semValue = Scalar\\Float_::fromString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            570 => null,\n            571 => null,\n            572 => null,\n            573 => static function ($self, $stackPos) {\n                 $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);\n            },\n            574 => static function ($self, $stackPos) {\n                 $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);\n            },\n            575 => static function ($self, $stackPos) {\n                 $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);\n            },\n            576 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            577 => null,\n            578 => null,\n            579 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            580 => null,\n            581 => null,\n            582 => null,\n            583 => null,\n            584 => null,\n            585 => null,\n            586 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            587 => null,\n            588 => null,\n            589 => null,\n            590 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            591 => null,\n            592 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            593 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            594 => static function ($self, $stackPos) {\n                 $self->semValue = null;\n            },\n            595 => null,\n            596 => null,\n            597 => null,\n            598 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            599 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            600 => null,\n            601 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(4-3)], $self->getAttributes($self->tokenStartStack[$stackPos-(4-1)], $self->tokenEndStack[$stackPos]));\n            },\n            602 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            603 => static function ($self, $stackPos) {\n                 $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;\n            },\n            604 => static function ($self, $stackPos) {\n                 $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;\n            },\n            605 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            606 => null,\n            607 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            608 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            609 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            610 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            611 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            612 => null,\n            613 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            614 => null,\n            615 => null,\n            616 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            617 => null,\n            618 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Error($self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos])); $self->errorState = 2;\n            },\n            619 => static function ($self, $stackPos) {\n                 $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);\n            $self->postprocessList($self->semValue);\n            },\n            620 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(1-1)]; $end = count($self->semValue)-1; if ($self->semValue[$end]->value instanceof Expr\\Error) array_pop($self->semValue);\n            },\n            621 => null,\n            622 => static function ($self, $stackPos) {\n                 /* do nothing -- prevent default action of $$=$self->semStack[$1]. See $551. */\n            },\n            623 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(3-1)][] = $self->semStack[$stackPos-(3-3)]; $self->semValue = $self->semStack[$stackPos-(3-1)];\n            },\n            624 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            625 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            626 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(2-2)], null, true, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            627 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(1-1)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            628 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            629 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            630 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            631 => static function ($self, $stackPos) {\n                 $self->semValue = new Node\\ArrayItem($self->semStack[$stackPos-(2-2)], null, false, $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]), true);\n            },\n            632 => static function ($self, $stackPos) {\n                 /* Create an Error node now to remember the position. We'll later either report an error,\n             or convert this into a null element, depending on whether this is a creation or destructuring context. */\n          $attrs = $self->createEmptyElemAttributes($self->tokenPos);\n          $self->semValue = new Node\\ArrayItem(new Expr\\Error($attrs), null, false, $attrs);\n            },\n            633 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            634 => static function ($self, $stackPos) {\n                 $self->semStack[$stackPos-(2-1)][] = $self->semStack[$stackPos-(2-2)]; $self->semValue = $self->semStack[$stackPos-(2-1)];\n            },\n            635 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(1-1)]);\n            },\n            636 => static function ($self, $stackPos) {\n                 $self->semValue = array($self->semStack[$stackPos-(2-1)], $self->semStack[$stackPos-(2-2)]);\n            },\n            637 => static function ($self, $stackPos) {\n                 $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);\n            },\n            638 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            639 => null,\n            640 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            641 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            642 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            643 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            644 => static function ($self, $stackPos) {\n                 $self->semValue = new Expr\\Variable($self->semStack[$stackPos-(3-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(3-1)], $self->tokenEndStack[$stackPos]));\n            },\n            645 => static function ($self, $stackPos) {\n                 $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]));\n            },\n            646 => static function ($self, $stackPos) {\n                 $self->semValue = $self->semStack[$stackPos-(3-2)];\n            },\n            647 => static function ($self, $stackPos) {\n                 $self->semValue = new Scalar\\String_($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            648 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseNumString($self->semStack[$stackPos-(1-1)], $self->getAttributes($self->tokenStartStack[$stackPos-(1-1)], $self->tokenEndStack[$stackPos]));\n            },\n            649 => static function ($self, $stackPos) {\n                 $self->semValue = $self->parseNumString('-' . $self->semStack[$stackPos-(2-2)], $self->getAttributes($self->tokenStartStack[$stackPos-(2-1)], $self->tokenEndStack[$stackPos]));\n            },\n            650 => null,\n        ];\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Parser.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\ninterface Parser {\n    /**\n     * Parses PHP code into a node tree.\n     *\n     * @param string $code The source code to parse\n     * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults\n     *                                        to ErrorHandler\\Throwing.\n     *\n     * @return Node\\Stmt[]|null Array of statements (or null non-throwing error handler is used and\n     *                          the parser was unable to recover from an error).\n     */\n    public function parse(string $code, ?ErrorHandler $errorHandler = null): ?array;\n\n    /**\n     * Return tokens for the last parse.\n     *\n     * @return Token[]\n     */\n    public function getTokens(): array;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ParserAbstract.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\n/*\n * This parser is based on a skeleton written by Moriyoshi Koizumi, which in\n * turn is based on work by Masato Bito.\n */\n\nuse PhpParser\\Node\\Arg;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Expr\\Array_;\nuse PhpParser\\Node\\Expr\\Cast\\Double;\nuse PhpParser\\Node\\Identifier;\nuse PhpParser\\Node\\InterpolatedStringPart;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Param;\nuse PhpParser\\Node\\PropertyHook;\nuse PhpParser\\Node\\Scalar\\InterpolatedString;\nuse PhpParser\\Node\\Scalar\\Int_;\nuse PhpParser\\Node\\Scalar\\String_;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\Node\\Stmt\\Class_;\nuse PhpParser\\Node\\Stmt\\ClassConst;\nuse PhpParser\\Node\\Stmt\\ClassMethod;\nuse PhpParser\\Node\\Stmt\\Const_;\nuse PhpParser\\Node\\Stmt\\Else_;\nuse PhpParser\\Node\\Stmt\\ElseIf_;\nuse PhpParser\\Node\\Stmt\\Enum_;\nuse PhpParser\\Node\\Stmt\\Interface_;\nuse PhpParser\\Node\\Stmt\\Namespace_;\nuse PhpParser\\Node\\Stmt\\Nop;\nuse PhpParser\\Node\\Stmt\\Property;\nuse PhpParser\\Node\\Stmt\\TryCatch;\nuse PhpParser\\Node\\UseItem;\nuse PhpParser\\Node\\VarLikeIdentifier;\nuse PhpParser\\NodeVisitor\\CommentAnnotatingVisitor;\n\nabstract class ParserAbstract implements Parser {\n    private const SYMBOL_NONE = -1;\n\n    /** @var Lexer Lexer that is used when parsing */\n    protected Lexer $lexer;\n    /** @var PhpVersion PHP version to target on a best-effort basis */\n    protected PhpVersion $phpVersion;\n\n    /*\n     * The following members will be filled with generated parsing data:\n     */\n\n    /** @var int Size of $tokenToSymbol map */\n    protected int $tokenToSymbolMapSize;\n    /** @var int Size of $action table */\n    protected int $actionTableSize;\n    /** @var int Size of $goto table */\n    protected int $gotoTableSize;\n\n    /** @var int Symbol number signifying an invalid token */\n    protected int $invalidSymbol;\n    /** @var int Symbol number of error recovery token */\n    protected int $errorSymbol;\n    /** @var int Action number signifying default action */\n    protected int $defaultAction;\n    /** @var int Rule number signifying that an unexpected token was encountered */\n    protected int $unexpectedTokenRule;\n\n    protected int $YY2TBLSTATE;\n    /** @var int Number of non-leaf states */\n    protected int $numNonLeafStates;\n\n    /** @var int[] Map of PHP token IDs to internal symbols */\n    protected array $phpTokenToSymbol;\n    /** @var array<int, bool> Map of PHP token IDs to drop */\n    protected array $dropTokens;\n    /** @var int[] Map of external symbols (static::T_*) to internal symbols */\n    protected array $tokenToSymbol;\n    /** @var string[] Map of symbols to their names */\n    protected array $symbolToName;\n    /** @var array<int, string> Names of the production rules (only necessary for debugging) */\n    protected array $productions;\n\n    /** @var int[] Map of states to a displacement into the $action table. The corresponding action for this\n     *             state/symbol pair is $action[$actionBase[$state] + $symbol]. If $actionBase[$state] is 0, the\n     *             action is defaulted, i.e. $actionDefault[$state] should be used instead. */\n    protected array $actionBase;\n    /** @var int[] Table of actions. Indexed according to $actionBase comment. */\n    protected array $action;\n    /** @var int[] Table indexed analogously to $action. If $actionCheck[$actionBase[$state] + $symbol] != $symbol\n     *             then the action is defaulted, i.e. $actionDefault[$state] should be used instead. */\n    protected array $actionCheck;\n    /** @var int[] Map of states to their default action */\n    protected array $actionDefault;\n    /** @var callable[] Semantic action callbacks */\n    protected array $reduceCallbacks;\n\n    /** @var int[] Map of non-terminals to a displacement into the $goto table. The corresponding goto state for this\n     *             non-terminal/state pair is $goto[$gotoBase[$nonTerminal] + $state] (unless defaulted) */\n    protected array $gotoBase;\n    /** @var int[] Table of states to goto after reduction. Indexed according to $gotoBase comment. */\n    protected array $goto;\n    /** @var int[] Table indexed analogously to $goto. If $gotoCheck[$gotoBase[$nonTerminal] + $state] != $nonTerminal\n     *             then the goto state is defaulted, i.e. $gotoDefault[$nonTerminal] should be used. */\n    protected array $gotoCheck;\n    /** @var int[] Map of non-terminals to the default state to goto after their reduction */\n    protected array $gotoDefault;\n\n    /** @var int[] Map of rules to the non-terminal on their left-hand side, i.e. the non-terminal to use for\n     *             determining the state to goto after reduction. */\n    protected array $ruleToNonTerminal;\n    /** @var int[] Map of rules to the length of their right-hand side, which is the number of elements that have to\n     *             be popped from the stack(s) on reduction. */\n    protected array $ruleToLength;\n\n    /*\n     * The following members are part of the parser state:\n     */\n\n    /** @var mixed Temporary value containing the result of last semantic action (reduction) */\n    protected $semValue;\n    /** @var mixed[] Semantic value stack (contains values of tokens and semantic action results) */\n    protected array $semStack;\n    /** @var int[] Token start position stack */\n    protected array $tokenStartStack;\n    /** @var int[] Token end position stack */\n    protected array $tokenEndStack;\n\n    /** @var ErrorHandler Error handler */\n    protected ErrorHandler $errorHandler;\n    /** @var int Error state, used to avoid error floods */\n    protected int $errorState;\n\n    /** @var \\SplObjectStorage<Array_, null>|null Array nodes created during parsing, for postprocessing of empty elements. */\n    protected ?\\SplObjectStorage $createdArrays;\n\n    /** @var \\SplObjectStorage<Expr\\ArrowFunction, null>|null\n     *       Arrow functions that are wrapped in parentheses, to enforce the pipe operator parentheses requirements.\n     */\n    protected ?\\SplObjectStorage $parenthesizedArrowFunctions;\n\n    /** @var Token[] Tokens for the current parse */\n    protected array $tokens;\n    /** @var int Current position in token array */\n    protected int $tokenPos;\n\n    /**\n     * Initialize $reduceCallbacks map.\n     */\n    abstract protected function initReduceCallbacks(): void;\n\n    /**\n     * Creates a parser instance.\n     *\n     * Options:\n     *  * phpVersion: ?PhpVersion,\n     *\n     * @param Lexer $lexer A lexer\n     * @param PhpVersion $phpVersion PHP version to target, defaults to latest supported. This\n     *                               option is best-effort: Even if specified, parsing will generally assume the latest\n     *                               supported version and only adjust behavior in minor ways, for example by omitting\n     *                               errors in older versions and interpreting type hints as a name or identifier depending\n     *                               on version.\n     */\n    public function __construct(Lexer $lexer, ?PhpVersion $phpVersion = null) {\n        $this->lexer = $lexer;\n        $this->phpVersion = $phpVersion ?? PhpVersion::getNewestSupported();\n\n        $this->initReduceCallbacks();\n        $this->phpTokenToSymbol = $this->createTokenMap();\n        $this->dropTokens = array_fill_keys(\n            [\\T_WHITESPACE, \\T_OPEN_TAG, \\T_COMMENT, \\T_DOC_COMMENT, \\T_BAD_CHARACTER], true\n        );\n    }\n\n    /**\n     * Parses PHP code into a node tree.\n     *\n     * If a non-throwing error handler is used, the parser will continue parsing after an error\n     * occurred and attempt to build a partial AST.\n     *\n     * @param string $code The source code to parse\n     * @param ErrorHandler|null $errorHandler Error handler to use for lexer/parser errors, defaults\n     *                                        to ErrorHandler\\Throwing.\n     *\n     * @return Node\\Stmt[]|null Array of statements (or null non-throwing error handler is used and\n     *                          the parser was unable to recover from an error).\n     */\n    public function parse(string $code, ?ErrorHandler $errorHandler = null): ?array {\n        $this->errorHandler = $errorHandler ?: new ErrorHandler\\Throwing();\n        $this->createdArrays = new \\SplObjectStorage();\n        $this->parenthesizedArrowFunctions = new \\SplObjectStorage();\n\n        $this->tokens = $this->lexer->tokenize($code, $this->errorHandler);\n        $result = $this->doParse();\n\n        // Report errors for any empty elements used inside arrays. This is delayed until after the main parse,\n        // because we don't know a priori whether a given array expression will be used in a destructuring context\n        // or not.\n        foreach ($this->createdArrays as $node) {\n            foreach ($node->items as $item) {\n                if ($item->value instanceof Expr\\Error) {\n                    $this->errorHandler->handleError(\n                        new Error('Cannot use empty array elements in arrays', $item->getAttributes()));\n                }\n            }\n        }\n\n        // Clear out some of the interior state, so we don't hold onto unnecessary\n        // memory between uses of the parser\n        $this->tokenStartStack = [];\n        $this->tokenEndStack = [];\n        $this->semStack = [];\n        $this->semValue = null;\n        $this->createdArrays = null;\n        $this->parenthesizedArrowFunctions = null;\n\n        if ($result !== null) {\n            $traverser = new NodeTraverser(new CommentAnnotatingVisitor($this->tokens));\n            $traverser->traverse($result);\n        }\n\n        return $result;\n    }\n\n    public function getTokens(): array {\n        return $this->tokens;\n    }\n\n    /** @return Stmt[]|null */\n    protected function doParse(): ?array {\n        // We start off with no lookahead-token\n        $symbol = self::SYMBOL_NONE;\n        $tokenValue = null;\n        $this->tokenPos = -1;\n\n        // Keep stack of start and end attributes\n        $this->tokenStartStack = [];\n        $this->tokenEndStack = [0];\n\n        // Start off in the initial state and keep a stack of previous states\n        $state = 0;\n        $stateStack = [$state];\n\n        // Semantic value stack (contains values of tokens and semantic action results)\n        $this->semStack = [];\n\n        // Current position in the stack(s)\n        $stackPos = 0;\n\n        $this->errorState = 0;\n\n        for (;;) {\n            //$this->traceNewState($state, $symbol);\n\n            if ($this->actionBase[$state] === 0) {\n                $rule = $this->actionDefault[$state];\n            } else {\n                if ($symbol === self::SYMBOL_NONE) {\n                    do {\n                        $token = $this->tokens[++$this->tokenPos];\n                        $tokenId = $token->id;\n                    } while (isset($this->dropTokens[$tokenId]));\n\n                    // Map the lexer token id to the internally used symbols.\n                    $tokenValue = $token->text;\n                    if (!isset($this->phpTokenToSymbol[$tokenId])) {\n                        throw new \\RangeException(sprintf(\n                            'The lexer returned an invalid token (id=%d, value=%s)',\n                            $tokenId, $tokenValue\n                        ));\n                    }\n                    $symbol = $this->phpTokenToSymbol[$tokenId];\n\n                    //$this->traceRead($symbol);\n                }\n\n                $idx = $this->actionBase[$state] + $symbol;\n                if ((($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol)\n                     || ($state < $this->YY2TBLSTATE\n                         && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0\n                         && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol))\n                    && ($action = $this->action[$idx]) !== $this->defaultAction) {\n                    /*\n                     * >= numNonLeafStates: shift and reduce\n                     * > 0: shift\n                     * = 0: accept\n                     * < 0: reduce\n                     * = -YYUNEXPECTED: error\n                     */\n                    if ($action > 0) {\n                        /* shift */\n                        //$this->traceShift($symbol);\n\n                        ++$stackPos;\n                        $stateStack[$stackPos] = $state = $action;\n                        $this->semStack[$stackPos] = $tokenValue;\n                        $this->tokenStartStack[$stackPos] = $this->tokenPos;\n                        $this->tokenEndStack[$stackPos] = $this->tokenPos;\n                        $symbol = self::SYMBOL_NONE;\n\n                        if ($this->errorState) {\n                            --$this->errorState;\n                        }\n\n                        if ($action < $this->numNonLeafStates) {\n                            continue;\n                        }\n\n                        /* $yyn >= numNonLeafStates means shift-and-reduce */\n                        $rule = $action - $this->numNonLeafStates;\n                    } else {\n                        $rule = -$action;\n                    }\n                } else {\n                    $rule = $this->actionDefault[$state];\n                }\n            }\n\n            for (;;) {\n                if ($rule === 0) {\n                    /* accept */\n                    //$this->traceAccept();\n                    return $this->semValue;\n                }\n                if ($rule !== $this->unexpectedTokenRule) {\n                    /* reduce */\n                    //$this->traceReduce($rule);\n\n                    $ruleLength = $this->ruleToLength[$rule];\n                    try {\n                        $callback = $this->reduceCallbacks[$rule];\n                        if ($callback !== null) {\n                            $callback($this, $stackPos);\n                        } elseif ($ruleLength > 0) {\n                            $this->semValue = $this->semStack[$stackPos - $ruleLength + 1];\n                        }\n                    } catch (Error $e) {\n                        if (-1 === $e->getStartLine()) {\n                            $e->setStartLine($this->tokens[$this->tokenPos]->line);\n                        }\n\n                        $this->emitError($e);\n                        // Can't recover from this type of error\n                        return null;\n                    }\n\n                    /* Goto - shift nonterminal */\n                    $lastTokenEnd = $this->tokenEndStack[$stackPos];\n                    $stackPos -= $ruleLength;\n                    $nonTerminal = $this->ruleToNonTerminal[$rule];\n                    $idx = $this->gotoBase[$nonTerminal] + $stateStack[$stackPos];\n                    if ($idx >= 0 && $idx < $this->gotoTableSize && $this->gotoCheck[$idx] === $nonTerminal) {\n                        $state = $this->goto[$idx];\n                    } else {\n                        $state = $this->gotoDefault[$nonTerminal];\n                    }\n\n                    ++$stackPos;\n                    $stateStack[$stackPos]     = $state;\n                    $this->semStack[$stackPos] = $this->semValue;\n                    $this->tokenEndStack[$stackPos] = $lastTokenEnd;\n                    if ($ruleLength === 0) {\n                        // Empty productions use the start attributes of the lookahead token.\n                        $this->tokenStartStack[$stackPos] = $this->tokenPos;\n                    }\n                } else {\n                    /* error */\n                    switch ($this->errorState) {\n                        case 0:\n                            $msg = $this->getErrorMessage($symbol, $state);\n                            $this->emitError(new Error($msg, $this->getAttributesForToken($this->tokenPos)));\n                            // Break missing intentionally\n                            // no break\n                        case 1:\n                        case 2:\n                            $this->errorState = 3;\n\n                            // Pop until error-expecting state uncovered\n                            while (!(\n                                (($idx = $this->actionBase[$state] + $this->errorSymbol) >= 0\n                                    && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol)\n                                || ($state < $this->YY2TBLSTATE\n                                    && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $this->errorSymbol) >= 0\n                                    && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $this->errorSymbol)\n                            ) || ($action = $this->action[$idx]) === $this->defaultAction) { // Not totally sure about this\n                                if ($stackPos <= 0) {\n                                    // Could not recover from error\n                                    return null;\n                                }\n                                $state = $stateStack[--$stackPos];\n                                //$this->tracePop($state);\n                            }\n\n                            //$this->traceShift($this->errorSymbol);\n                            ++$stackPos;\n                            $stateStack[$stackPos] = $state = $action;\n\n                            // We treat the error symbol as being empty, so we reset the end attributes\n                            // to the end attributes of the last non-error symbol\n                            $this->tokenStartStack[$stackPos] = $this->tokenPos;\n                            $this->tokenEndStack[$stackPos] = $this->tokenEndStack[$stackPos - 1];\n                            break;\n\n                        case 3:\n                            if ($symbol === 0) {\n                                // Reached EOF without recovering from error\n                                return null;\n                            }\n\n                            //$this->traceDiscard($symbol);\n                            $symbol = self::SYMBOL_NONE;\n                            break 2;\n                    }\n                }\n\n                if ($state < $this->numNonLeafStates) {\n                    break;\n                }\n\n                /* >= numNonLeafStates means shift-and-reduce */\n                $rule = $state - $this->numNonLeafStates;\n            }\n        }\n    }\n\n    protected function emitError(Error $error): void {\n        $this->errorHandler->handleError($error);\n    }\n\n    /**\n     * Format error message including expected tokens.\n     *\n     * @param int $symbol Unexpected symbol\n     * @param int $state State at time of error\n     *\n     * @return string Formatted error message\n     */\n    protected function getErrorMessage(int $symbol, int $state): string {\n        $expectedString = '';\n        if ($expected = $this->getExpectedTokens($state)) {\n            $expectedString = ', expecting ' . implode(' or ', $expected);\n        }\n\n        return 'Syntax error, unexpected ' . $this->symbolToName[$symbol] . $expectedString;\n    }\n\n    /**\n     * Get limited number of expected tokens in given state.\n     *\n     * @param int $state State\n     *\n     * @return string[] Expected tokens. If too many, an empty array is returned.\n     */\n    protected function getExpectedTokens(int $state): array {\n        $expected = [];\n\n        $base = $this->actionBase[$state];\n        foreach ($this->symbolToName as $symbol => $name) {\n            $idx = $base + $symbol;\n            if ($idx >= 0 && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol\n                || $state < $this->YY2TBLSTATE\n                && ($idx = $this->actionBase[$state + $this->numNonLeafStates] + $symbol) >= 0\n                && $idx < $this->actionTableSize && $this->actionCheck[$idx] === $symbol\n            ) {\n                if ($this->action[$idx] !== $this->unexpectedTokenRule\n                    && $this->action[$idx] !== $this->defaultAction\n                    && $symbol !== $this->errorSymbol\n                ) {\n                    if (count($expected) === 4) {\n                        /* Too many expected tokens */\n                        return [];\n                    }\n\n                    $expected[] = $name;\n                }\n            }\n        }\n\n        return $expected;\n    }\n\n    /**\n     * Get attributes for a node with the given start and end token positions.\n     *\n     * @param int $tokenStartPos Token position the node starts at\n     * @param int $tokenEndPos Token position the node ends at\n     * @return array<string, mixed> Attributes\n     */\n    protected function getAttributes(int $tokenStartPos, int $tokenEndPos): array {\n        $startToken = $this->tokens[$tokenStartPos];\n        $afterEndToken = $this->tokens[$tokenEndPos + 1];\n        return [\n            'startLine' => $startToken->line,\n            'startTokenPos' => $tokenStartPos,\n            'startFilePos' => $startToken->pos,\n            'endLine' => $afterEndToken->line,\n            'endTokenPos' => $tokenEndPos,\n            'endFilePos' => $afterEndToken->pos - 1,\n        ];\n    }\n\n    /**\n     * Get attributes for a single token at the given token position.\n     *\n     * @return array<string, mixed> Attributes\n     */\n    protected function getAttributesForToken(int $tokenPos): array {\n        if ($tokenPos < \\count($this->tokens) - 1) {\n            return $this->getAttributes($tokenPos, $tokenPos);\n        }\n\n        // Get attributes for the sentinel token.\n        $token = $this->tokens[$tokenPos];\n        return [\n            'startLine' => $token->line,\n            'startTokenPos' => $tokenPos,\n            'startFilePos' => $token->pos,\n            'endLine' => $token->line,\n            'endTokenPos' => $tokenPos,\n            'endFilePos' => $token->pos,\n        ];\n    }\n\n    /*\n     * Tracing functions used for debugging the parser.\n     */\n\n    /*\n    protected function traceNewState($state, $symbol): void {\n        echo '% State ' . $state\n            . ', Lookahead ' . ($symbol == self::SYMBOL_NONE ? '--none--' : $this->symbolToName[$symbol]) . \"\\n\";\n    }\n\n    protected function traceRead($symbol): void {\n        echo '% Reading ' . $this->symbolToName[$symbol] . \"\\n\";\n    }\n\n    protected function traceShift($symbol): void {\n        echo '% Shift ' . $this->symbolToName[$symbol] . \"\\n\";\n    }\n\n    protected function traceAccept(): void {\n        echo \"% Accepted.\\n\";\n    }\n\n    protected function traceReduce($n): void {\n        echo '% Reduce by (' . $n . ') ' . $this->productions[$n] . \"\\n\";\n    }\n\n    protected function tracePop($state): void {\n        echo '% Recovering, uncovered state ' . $state . \"\\n\";\n    }\n\n    protected function traceDiscard($symbol): void {\n        echo '% Discard ' . $this->symbolToName[$symbol] . \"\\n\";\n    }\n    */\n\n    /*\n     * Helper functions invoked by semantic actions\n     */\n\n    /**\n     * Moves statements of semicolon-style namespaces into $ns->stmts and checks various error conditions.\n     *\n     * @param Node\\Stmt[] $stmts\n     * @return Node\\Stmt[]\n     */\n    protected function handleNamespaces(array $stmts): array {\n        $hasErrored = false;\n        $style = $this->getNamespacingStyle($stmts);\n        if (null === $style) {\n            // not namespaced, nothing to do\n            return $stmts;\n        }\n        if ('brace' === $style) {\n            // For braced namespaces we only have to check that there are no invalid statements between the namespaces\n            $afterFirstNamespace = false;\n            foreach ($stmts as $stmt) {\n                if ($stmt instanceof Node\\Stmt\\Namespace_) {\n                    $afterFirstNamespace = true;\n                } elseif (!$stmt instanceof Node\\Stmt\\HaltCompiler\n                        && !$stmt instanceof Node\\Stmt\\Nop\n                        && $afterFirstNamespace && !$hasErrored) {\n                    $this->emitError(new Error(\n                        'No code may exist outside of namespace {}', $stmt->getAttributes()));\n                    $hasErrored = true; // Avoid one error for every statement\n                }\n            }\n            return $stmts;\n        } else {\n            // For semicolon namespaces we have to move the statements after a namespace declaration into ->stmts\n            $resultStmts = [];\n            $targetStmts = &$resultStmts;\n            $lastNs = null;\n            foreach ($stmts as $stmt) {\n                if ($stmt instanceof Node\\Stmt\\Namespace_) {\n                    if ($lastNs !== null) {\n                        $this->fixupNamespaceAttributes($lastNs);\n                    }\n                    if ($stmt->stmts === null) {\n                        $stmt->stmts = [];\n                        $targetStmts = &$stmt->stmts;\n                        $resultStmts[] = $stmt;\n                    } else {\n                        // This handles the invalid case of mixed style namespaces\n                        $resultStmts[] = $stmt;\n                        $targetStmts = &$resultStmts;\n                    }\n                    $lastNs = $stmt;\n                } elseif ($stmt instanceof Node\\Stmt\\HaltCompiler) {\n                    // __halt_compiler() is not moved into the namespace\n                    $resultStmts[] = $stmt;\n                } else {\n                    $targetStmts[] = $stmt;\n                }\n            }\n            if ($lastNs !== null) {\n                $this->fixupNamespaceAttributes($lastNs);\n            }\n            return $resultStmts;\n        }\n    }\n\n    private function fixupNamespaceAttributes(Node\\Stmt\\Namespace_ $stmt): void {\n        // We moved the statements into the namespace node, as such the end of the namespace node\n        // needs to be extended to the end of the statements.\n        if (empty($stmt->stmts)) {\n            return;\n        }\n\n        // We only move the builtin end attributes here. This is the best we can do with the\n        // knowledge we have.\n        $endAttributes = ['endLine', 'endFilePos', 'endTokenPos'];\n        $lastStmt = $stmt->stmts[count($stmt->stmts) - 1];\n        foreach ($endAttributes as $endAttribute) {\n            if ($lastStmt->hasAttribute($endAttribute)) {\n                $stmt->setAttribute($endAttribute, $lastStmt->getAttribute($endAttribute));\n            }\n        }\n    }\n\n    /** @return array<string, mixed> */\n    private function getNamespaceErrorAttributes(Namespace_ $node): array {\n        $attrs = $node->getAttributes();\n        // Adjust end attributes to only cover the \"namespace\" keyword, not the whole namespace.\n        if (isset($attrs['startLine'])) {\n            $attrs['endLine'] = $attrs['startLine'];\n        }\n        if (isset($attrs['startTokenPos'])) {\n            $attrs['endTokenPos'] = $attrs['startTokenPos'];\n        }\n        if (isset($attrs['startFilePos'])) {\n            $attrs['endFilePos'] = $attrs['startFilePos'] + \\strlen('namespace') - 1;\n        }\n        return $attrs;\n    }\n\n    /**\n     * Determine namespacing style (semicolon or brace)\n     *\n     * @param Node[] $stmts Top-level statements.\n     *\n     * @return null|string One of \"semicolon\", \"brace\" or null (no namespaces)\n     */\n    private function getNamespacingStyle(array $stmts): ?string {\n        $style = null;\n        $hasNotAllowedStmts = false;\n        foreach ($stmts as $i => $stmt) {\n            if ($stmt instanceof Node\\Stmt\\Namespace_) {\n                $currentStyle = null === $stmt->stmts ? 'semicolon' : 'brace';\n                if (null === $style) {\n                    $style = $currentStyle;\n                    if ($hasNotAllowedStmts) {\n                        $this->emitError(new Error(\n                            'Namespace declaration statement has to be the very first statement in the script',\n                            $this->getNamespaceErrorAttributes($stmt)\n                        ));\n                    }\n                } elseif ($style !== $currentStyle) {\n                    $this->emitError(new Error(\n                        'Cannot mix bracketed namespace declarations with unbracketed namespace declarations',\n                        $this->getNamespaceErrorAttributes($stmt)\n                    ));\n                    // Treat like semicolon style for namespace normalization\n                    return 'semicolon';\n                }\n                continue;\n            }\n\n            /* declare(), __halt_compiler() and nops can be used before a namespace declaration */\n            if ($stmt instanceof Node\\Stmt\\Declare_\n                || $stmt instanceof Node\\Stmt\\HaltCompiler\n                || $stmt instanceof Node\\Stmt\\Nop) {\n                continue;\n            }\n\n            /* There may be a hashbang line at the very start of the file */\n            if ($i === 0 && $stmt instanceof Node\\Stmt\\InlineHTML && preg_match('/\\A#!.*\\r?\\n\\z/', $stmt->value)) {\n                continue;\n            }\n\n            /* Everything else if forbidden before namespace declarations */\n            $hasNotAllowedStmts = true;\n        }\n        return $style;\n    }\n\n    /** @return Name|Identifier */\n    protected function handleBuiltinTypes(Name $name) {\n        if (!$name->isUnqualified()) {\n            return $name;\n        }\n\n        $lowerName = $name->toLowerString();\n        if (!$this->phpVersion->supportsBuiltinType($lowerName)) {\n            return $name;\n        }\n\n        return new Node\\Identifier($lowerName, $name->getAttributes());\n    }\n\n    /**\n     * Get combined start and end attributes at a stack location\n     *\n     * @param int $stackPos Stack location\n     *\n     * @return array<string, mixed> Combined start and end attributes\n     */\n    protected function getAttributesAt(int $stackPos): array {\n        return $this->getAttributes($this->tokenStartStack[$stackPos], $this->tokenEndStack[$stackPos]);\n    }\n\n    protected function getFloatCastKind(string $cast): int {\n        $cast = strtolower($cast);\n        if (strpos($cast, 'float') !== false) {\n            return Double::KIND_FLOAT;\n        }\n\n        if (strpos($cast, 'real') !== false) {\n            return Double::KIND_REAL;\n        }\n\n        return Double::KIND_DOUBLE;\n    }\n\n    protected function getIntCastKind(string $cast): int {\n        $cast = strtolower($cast);\n        if (strpos($cast, 'integer') !== false) {\n            return Expr\\Cast\\Int_::KIND_INTEGER;\n        }\n\n        return Expr\\Cast\\Int_::KIND_INT;\n    }\n\n    protected function getBoolCastKind(string $cast): int {\n        $cast = strtolower($cast);\n        if (strpos($cast, 'boolean') !== false) {\n            return Expr\\Cast\\Bool_::KIND_BOOLEAN;\n        }\n\n        return Expr\\Cast\\Bool_::KIND_BOOL;\n    }\n\n    protected function getStringCastKind(string $cast): int {\n        $cast = strtolower($cast);\n        if (strpos($cast, 'binary') !== false) {\n            return Expr\\Cast\\String_::KIND_BINARY;\n        }\n\n        return Expr\\Cast\\String_::KIND_STRING;\n    }\n\n    /** @param array<string, mixed> $attributes */\n    protected function parseLNumber(string $str, array $attributes, bool $allowInvalidOctal = false): Int_ {\n        try {\n            return Int_::fromString($str, $attributes, $allowInvalidOctal);\n        } catch (Error $error) {\n            $this->emitError($error);\n            // Use dummy value\n            return new Int_(0, $attributes);\n        }\n    }\n\n    /**\n     * Parse a T_NUM_STRING token into either an integer or string node.\n     *\n     * @param string $str Number string\n     * @param array<string, mixed> $attributes Attributes\n     *\n     * @return Int_|String_ Integer or string node.\n     */\n    protected function parseNumString(string $str, array $attributes) {\n        if (!preg_match('/^(?:0|-?[1-9][0-9]*)$/', $str)) {\n            return new String_($str, $attributes);\n        }\n\n        $num = +$str;\n        if (!is_int($num)) {\n            return new String_($str, $attributes);\n        }\n\n        return new Int_($num, $attributes);\n    }\n\n    /** @param array<string, mixed> $attributes */\n    protected function stripIndentation(\n        string $string, int $indentLen, string $indentChar,\n        bool $newlineAtStart, bool $newlineAtEnd, array $attributes\n    ): string {\n        if ($indentLen === 0) {\n            return $string;\n        }\n\n        $start = $newlineAtStart ? '(?:(?<=\\n)|\\A)' : '(?<=\\n)';\n        $end = $newlineAtEnd ? '(?:(?=[\\r\\n])|\\z)' : '(?=[\\r\\n])';\n        $regex = '/' . $start . '([ \\t]*)(' . $end . ')?/';\n        return preg_replace_callback(\n            $regex,\n            function ($matches) use ($indentLen, $indentChar, $attributes) {\n                $prefix = substr($matches[1], 0, $indentLen);\n                if (false !== strpos($prefix, $indentChar === \" \" ? \"\\t\" : \" \")) {\n                    $this->emitError(new Error(\n                        'Invalid indentation - tabs and spaces cannot be mixed', $attributes\n                    ));\n                } elseif (strlen($prefix) < $indentLen && !isset($matches[2])) {\n                    $this->emitError(new Error(\n                        'Invalid body indentation level ' .\n                        '(expecting an indentation level of at least ' . $indentLen . ')',\n                        $attributes\n                    ));\n                }\n                return substr($matches[0], strlen($prefix));\n            },\n            $string\n        );\n    }\n\n    /**\n     * @param string|(Expr|InterpolatedStringPart)[] $contents\n     * @param array<string, mixed> $attributes\n     * @param array<string, mixed> $endTokenAttributes\n     */\n    protected function parseDocString(\n        string $startToken, $contents, string $endToken,\n        array $attributes, array $endTokenAttributes, bool $parseUnicodeEscape\n    ): Expr {\n        $kind = strpos($startToken, \"'\") === false\n            ? String_::KIND_HEREDOC : String_::KIND_NOWDOC;\n\n        $regex = '/\\A[bB]?<<<[ \\t]*[\\'\"]?([a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]*)[\\'\"]?(?:\\r\\n|\\n|\\r)\\z/';\n        $result = preg_match($regex, $startToken, $matches);\n        assert($result === 1);\n        $label = $matches[1];\n\n        $result = preg_match('/\\A[ \\t]*/', $endToken, $matches);\n        assert($result === 1);\n        $indentation = $matches[0];\n\n        $attributes['kind'] = $kind;\n        $attributes['docLabel'] = $label;\n        $attributes['docIndentation'] = $indentation;\n\n        $indentHasSpaces = false !== strpos($indentation, \" \");\n        $indentHasTabs = false !== strpos($indentation, \"\\t\");\n        if ($indentHasSpaces && $indentHasTabs) {\n            $this->emitError(new Error(\n                'Invalid indentation - tabs and spaces cannot be mixed',\n                $endTokenAttributes\n            ));\n\n            // Proceed processing as if this doc string is not indented\n            $indentation = '';\n        }\n\n        $indentLen = \\strlen($indentation);\n        $indentChar = $indentHasSpaces ? \" \" : \"\\t\";\n\n        if (\\is_string($contents)) {\n            if ($contents === '') {\n                $attributes['rawValue'] = $contents;\n                return new String_('', $attributes);\n            }\n\n            $contents = $this->stripIndentation(\n                $contents, $indentLen, $indentChar, true, true, $attributes\n            );\n            $contents = preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $contents);\n            $attributes['rawValue'] = $contents;\n\n            if ($kind === String_::KIND_HEREDOC) {\n                $contents = String_::parseEscapeSequences($contents, null, $parseUnicodeEscape);\n            }\n\n            return new String_($contents, $attributes);\n        } else {\n            assert(count($contents) > 0);\n            if (!$contents[0] instanceof Node\\InterpolatedStringPart) {\n                // If there is no leading encapsed string part, pretend there is an empty one\n                $this->stripIndentation(\n                    '', $indentLen, $indentChar, true, false, $contents[0]->getAttributes()\n                );\n            }\n\n            $newContents = [];\n            foreach ($contents as $i => $part) {\n                if ($part instanceof Node\\InterpolatedStringPart) {\n                    $isLast = $i === \\count($contents) - 1;\n                    $part->value = $this->stripIndentation(\n                        $part->value, $indentLen, $indentChar,\n                        $i === 0, $isLast, $part->getAttributes()\n                    );\n                    if ($isLast) {\n                        $part->value = preg_replace('~(\\r\\n|\\n|\\r)\\z~', '', $part->value);\n                    }\n                    $part->setAttribute('rawValue', $part->value);\n                    $part->value = String_::parseEscapeSequences($part->value, null, $parseUnicodeEscape);\n                    if ('' === $part->value) {\n                        continue;\n                    }\n                }\n                $newContents[] = $part;\n            }\n            return new InterpolatedString($newContents, $attributes);\n        }\n    }\n\n    protected function createCommentFromToken(Token $token, int $tokenPos): Comment {\n        assert($token->id === \\T_COMMENT || $token->id == \\T_DOC_COMMENT);\n        return \\T_DOC_COMMENT === $token->id\n            ? new Comment\\Doc($token->text, $token->line, $token->pos, $tokenPos,\n                $token->getEndLine(), $token->getEndPos() - 1, $tokenPos)\n            : new Comment($token->text, $token->line, $token->pos, $tokenPos,\n                $token->getEndLine(), $token->getEndPos() - 1, $tokenPos);\n    }\n\n    /**\n     * Get last comment before the given token position, if any\n     */\n    protected function getCommentBeforeToken(int $tokenPos): ?Comment {\n        while (--$tokenPos >= 0) {\n            $token = $this->tokens[$tokenPos];\n            if (!isset($this->dropTokens[$token->id])) {\n                break;\n            }\n\n            if ($token->id === \\T_COMMENT || $token->id === \\T_DOC_COMMENT) {\n                return $this->createCommentFromToken($token, $tokenPos);\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Create a zero-length nop to capture preceding comments, if any.\n     */\n    protected function maybeCreateZeroLengthNop(int $tokenPos): ?Nop {\n        $comment = $this->getCommentBeforeToken($tokenPos);\n        if ($comment === null) {\n            return null;\n        }\n\n        $commentEndLine = $comment->getEndLine();\n        $commentEndFilePos = $comment->getEndFilePos();\n        $commentEndTokenPos = $comment->getEndTokenPos();\n        $attributes = [\n            'startLine' => $commentEndLine,\n            'endLine' => $commentEndLine,\n            'startFilePos' => $commentEndFilePos + 1,\n            'endFilePos' => $commentEndFilePos,\n            'startTokenPos' => $commentEndTokenPos + 1,\n            'endTokenPos' => $commentEndTokenPos,\n        ];\n        return new Nop($attributes);\n    }\n\n    protected function maybeCreateNop(int $tokenStartPos, int $tokenEndPos): ?Nop {\n        if ($this->getCommentBeforeToken($tokenStartPos) === null) {\n            return null;\n        }\n        return new Nop($this->getAttributes($tokenStartPos, $tokenEndPos));\n    }\n\n    protected function handleHaltCompiler(): string {\n        // Prevent the lexer from returning any further tokens.\n        $nextToken = $this->tokens[$this->tokenPos + 1];\n        $this->tokenPos = \\count($this->tokens) - 2;\n\n        // Return text after __halt_compiler.\n        return $nextToken->id === \\T_INLINE_HTML ? $nextToken->text : '';\n    }\n\n    protected function inlineHtmlHasLeadingNewline(int $stackPos): bool {\n        $tokenPos = $this->tokenStartStack[$stackPos];\n        $token = $this->tokens[$tokenPos];\n        assert($token->id == \\T_INLINE_HTML);\n        if ($tokenPos > 0) {\n            $prevToken = $this->tokens[$tokenPos - 1];\n            assert($prevToken->id == \\T_CLOSE_TAG);\n            return false !== strpos($prevToken->text, \"\\n\")\n                || false !== strpos($prevToken->text, \"\\r\");\n        }\n        return true;\n    }\n\n    /**\n     * @return array<string, mixed>\n     */\n    protected function createEmptyElemAttributes(int $tokenPos): array {\n        return $this->getAttributesForToken($tokenPos);\n    }\n\n    protected function fixupArrayDestructuring(Array_ $node): Expr\\List_ {\n        $this->createdArrays->offsetUnset($node);\n        return new Expr\\List_(array_map(function (Node\\ArrayItem $item) {\n            if ($item->value instanceof Expr\\Error) {\n                // We used Error as a placeholder for empty elements, which are legal for destructuring.\n                return null;\n            }\n            if ($item->value instanceof Array_) {\n                return new Node\\ArrayItem(\n                    $this->fixupArrayDestructuring($item->value),\n                    $item->key, $item->byRef, $item->getAttributes());\n            }\n            return $item;\n        }, $node->items), ['kind' => Expr\\List_::KIND_ARRAY] + $node->getAttributes());\n    }\n\n    protected function postprocessList(Expr\\List_ $node): void {\n        foreach ($node->items as $i => $item) {\n            if ($item->value instanceof Expr\\Error) {\n                // We used Error as a placeholder for empty elements, which are legal for destructuring.\n                $node->items[$i] = null;\n            }\n        }\n    }\n\n    /** @param ElseIf_|Else_ $node */\n    protected function fixupAlternativeElse($node): void {\n        // Make sure a trailing nop statement carrying comments is part of the node.\n        $numStmts = \\count($node->stmts);\n        if ($numStmts !== 0 && $node->stmts[$numStmts - 1] instanceof Nop) {\n            $nopAttrs = $node->stmts[$numStmts - 1]->getAttributes();\n            if (isset($nopAttrs['endLine'])) {\n                $node->setAttribute('endLine', $nopAttrs['endLine']);\n            }\n            if (isset($nopAttrs['endFilePos'])) {\n                $node->setAttribute('endFilePos', $nopAttrs['endFilePos']);\n            }\n            if (isset($nopAttrs['endTokenPos'])) {\n                $node->setAttribute('endTokenPos', $nopAttrs['endTokenPos']);\n            }\n        }\n    }\n\n    protected function checkClassModifier(int $a, int $b, int $modifierPos): void {\n        try {\n            Modifiers::verifyClassModifier($a, $b);\n        } catch (Error $error) {\n            $error->setAttributes($this->getAttributesAt($modifierPos));\n            $this->emitError($error);\n        }\n    }\n\n    protected function checkModifier(int $a, int $b, int $modifierPos): void {\n        // Jumping through some hoops here because verifyModifier() is also used elsewhere\n        try {\n            Modifiers::verifyModifier($a, $b);\n        } catch (Error $error) {\n            $error->setAttributes($this->getAttributesAt($modifierPos));\n            $this->emitError($error);\n        }\n    }\n\n    protected function checkParam(Param $node): void {\n        if ($node->variadic && null !== $node->default) {\n            $this->emitError(new Error(\n                'Variadic parameter cannot have a default value',\n                $node->default->getAttributes()\n            ));\n        }\n\n        if ($node->type instanceof Identifier && $node->type->name === 'void') {\n            $this->emitError(new Error(\n                'void cannot be used as a parameter type',\n                $node->type->getAttributes()\n            ));\n        }\n    }\n\n    protected function checkTryCatch(TryCatch $node): void {\n        if (empty($node->catches) && null === $node->finally) {\n            $this->emitError(new Error(\n                'Cannot use try without catch or finally', $node->getAttributes()\n            ));\n        }\n    }\n\n    protected function checkNamespace(Namespace_ $node): void {\n        if (null !== $node->stmts) {\n            foreach ($node->stmts as $stmt) {\n                if ($stmt instanceof Namespace_) {\n                    $this->emitError(new Error(\n                        'Namespace declarations cannot be nested', $stmt->getAttributes()\n                    ));\n                }\n            }\n        }\n    }\n\n    private function checkClassName(?Identifier $name, int $namePos): void {\n        if (null !== $name && $name->isSpecialClassName()) {\n            $this->emitError(new Error(\n                sprintf('Cannot use \\'%s\\' as class name as it is reserved', $name),\n                $this->getAttributesAt($namePos)\n            ));\n        }\n    }\n\n    /** @param Name[] $interfaces */\n    private function checkImplementedInterfaces(array $interfaces): void {\n        foreach ($interfaces as $interface) {\n            if ($interface->isSpecialClassName()) {\n                $this->emitError(new Error(\n                    sprintf('Cannot use \\'%s\\' as interface name as it is reserved', $interface),\n                    $interface->getAttributes()\n                ));\n            }\n        }\n    }\n\n    protected function checkClass(Class_ $node, int $namePos): void {\n        $this->checkClassName($node->name, $namePos);\n\n        if ($node->extends && $node->extends->isSpecialClassName()) {\n            $this->emitError(new Error(\n                sprintf('Cannot use \\'%s\\' as class name as it is reserved', $node->extends),\n                $node->extends->getAttributes()\n            ));\n        }\n\n        $this->checkImplementedInterfaces($node->implements);\n    }\n\n    protected function checkInterface(Interface_ $node, int $namePos): void {\n        $this->checkClassName($node->name, $namePos);\n        $this->checkImplementedInterfaces($node->extends);\n    }\n\n    protected function checkEnum(Enum_ $node, int $namePos): void {\n        $this->checkClassName($node->name, $namePos);\n        $this->checkImplementedInterfaces($node->implements);\n    }\n\n    protected function checkClassMethod(ClassMethod $node, int $modifierPos): void {\n        if ($node->flags & Modifiers::STATIC) {\n            switch ($node->name->toLowerString()) {\n                case '__construct':\n                    $this->emitError(new Error(\n                        sprintf('Constructor %s() cannot be static', $node->name),\n                        $this->getAttributesAt($modifierPos)));\n                    break;\n                case '__destruct':\n                    $this->emitError(new Error(\n                        sprintf('Destructor %s() cannot be static', $node->name),\n                        $this->getAttributesAt($modifierPos)));\n                    break;\n                case '__clone':\n                    $this->emitError(new Error(\n                        sprintf('Clone method %s() cannot be static', $node->name),\n                        $this->getAttributesAt($modifierPos)));\n                    break;\n            }\n        }\n\n        if ($node->flags & Modifiers::READONLY) {\n            $this->emitError(new Error(\n                sprintf('Method %s() cannot be readonly', $node->name),\n                $this->getAttributesAt($modifierPos)));\n        }\n    }\n\n    protected function checkClassConst(ClassConst $node, int $modifierPos): void {\n        foreach ([Modifiers::STATIC, Modifiers::ABSTRACT, Modifiers::READONLY] as $modifier) {\n            if ($node->flags & $modifier) {\n                $this->emitError(new Error(\n                    \"Cannot use '\" . Modifiers::toString($modifier) . \"' as constant modifier\",\n                    $this->getAttributesAt($modifierPos)));\n            }\n        }\n    }\n\n    protected function checkUseUse(UseItem $node, int $namePos): void {\n        if ($node->alias && $node->alias->isSpecialClassName()) {\n            $this->emitError(new Error(\n                sprintf(\n                    'Cannot use %s as %s because \\'%2$s\\' is a special class name',\n                    $node->name, $node->alias\n                ),\n                $this->getAttributesAt($namePos)\n            ));\n        }\n    }\n\n    protected function checkPropertyHooksForMultiProperty(Property $property, int $hookPos): void {\n        if (count($property->props) > 1) {\n            $this->emitError(new Error(\n                'Cannot use hooks when declaring multiple properties', $this->getAttributesAt($hookPos)));\n        }\n    }\n\n    /** @param PropertyHook[] $hooks */\n    protected function checkEmptyPropertyHookList(array $hooks, int $hookPos): void {\n        if (empty($hooks)) {\n            $this->emitError(new Error(\n                'Property hook list cannot be empty', $this->getAttributesAt($hookPos)));\n        }\n    }\n\n    protected function checkPropertyHook(PropertyHook $hook, ?int $paramListPos): void {\n        $name = $hook->name->toLowerString();\n        if ($name !== 'get' && $name !== 'set') {\n            $this->emitError(new Error(\n                'Unknown hook \"' . $hook->name . '\", expected \"get\" or \"set\"',\n                $hook->name->getAttributes()));\n        }\n        if ($name === 'get' && $paramListPos !== null) {\n            $this->emitError(new Error(\n                'get hook must not have a parameter list', $this->getAttributesAt($paramListPos)));\n        }\n    }\n\n    protected function checkPropertyHookModifiers(int $a, int $b, int $modifierPos): void {\n        try {\n            Modifiers::verifyModifier($a, $b);\n        } catch (Error $error) {\n            $error->setAttributes($this->getAttributesAt($modifierPos));\n            $this->emitError($error);\n        }\n\n        if ($b != Modifiers::FINAL) {\n            $this->emitError(new Error(\n                'Cannot use the ' . Modifiers::toString($b) . ' modifier on a property hook',\n                $this->getAttributesAt($modifierPos)));\n        }\n    }\n\n    protected function checkConstantAttributes(Const_ $node): void {\n        if ($node->attrGroups !== [] && count($node->consts) > 1) {\n            $this->emitError(new Error(\n                'Cannot use attributes on multiple constants at once', $node->getAttributes()));\n        }\n    }\n\n    protected function checkPipeOperatorParentheses(Expr $node): void {\n        if ($node instanceof Expr\\ArrowFunction && !$this->parenthesizedArrowFunctions->offsetExists($node)) {\n            $this->emitError(new Error(\n                'Arrow functions on the right hand side of |> must be parenthesized', $node->getAttributes()));\n        }\n    }\n\n    /**\n     * @param Property|Param $node\n     */\n    protected function addPropertyNameToHooks(Node $node): void {\n        if ($node instanceof Property) {\n            $name = $node->props[0]->name->toString();\n        } else {\n            $name = $node->var->name;\n        }\n        foreach ($node->hooks as $hook) {\n            $hook->setAttribute('propertyName', $name);\n        }\n    }\n\n    /** @param array<Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder> $args */\n    private function isSimpleExit(array $args): bool {\n        if (\\count($args) === 0) {\n            return true;\n        }\n        if (\\count($args) === 1) {\n            $arg = $args[0];\n            return $arg instanceof Arg && $arg->name === null &&\n                   $arg->byRef === false && $arg->unpack === false;\n        }\n        return false;\n    }\n\n    /**\n     * @param array<Node\\Arg|Node\\VariadicPlaceholder|Node\\ArgPlaceholder> $args\n     * @param array<string, mixed> $attrs\n     */\n    protected function createExitExpr(string $name, int $namePos, array $args, array $attrs): Expr {\n        if ($this->isSimpleExit($args)) {\n            // Create Exit node for backwards compatibility.\n            $attrs['kind'] = strtolower($name) === 'exit' ? Expr\\Exit_::KIND_EXIT : Expr\\Exit_::KIND_DIE;\n            return new Expr\\Exit_(\\count($args) === 1 ? $args[0]->value : null, $attrs);\n        }\n        return new Expr\\FuncCall(new Name($name, $this->getAttributesAt($namePos)), $args, $attrs);\n    }\n\n    /**\n     * Creates the token map.\n     *\n     * The token map maps the PHP internal token identifiers\n     * to the identifiers used by the Parser. Additionally it\n     * maps T_OPEN_TAG_WITH_ECHO to T_ECHO and T_CLOSE_TAG to ';'.\n     *\n     * @return array<int, int> The token map\n     */\n    protected function createTokenMap(): array {\n        $tokenMap = [];\n\n        // Single-char tokens use an identity mapping.\n        for ($i = 0; $i < 256; ++$i) {\n            $tokenMap[$i] = $i;\n        }\n\n        foreach ($this->symbolToName as $name) {\n            if ($name[0] === 'T') {\n                $tokenMap[\\constant($name)] = constant(static::class . '::' . $name);\n            }\n        }\n\n        // T_OPEN_TAG_WITH_ECHO with dropped T_OPEN_TAG results in T_ECHO\n        $tokenMap[\\T_OPEN_TAG_WITH_ECHO] = static::T_ECHO;\n        // T_CLOSE_TAG is equivalent to ';'\n        $tokenMap[\\T_CLOSE_TAG] = ord(';');\n\n        // We have created a map from PHP token IDs to external symbol IDs.\n        // Now map them to the internal symbol ID.\n        $fullTokenMap = [];\n        foreach ($tokenMap as $phpToken => $extSymbol) {\n            $intSymbol = $this->tokenToSymbol[$extSymbol];\n            if ($intSymbol === $this->invalidSymbol) {\n                continue;\n            }\n            $fullTokenMap[$phpToken] = $intSymbol;\n        }\n\n        return $fullTokenMap;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/ParserFactory.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Parser\\Php7;\nuse PhpParser\\Parser\\Php8;\n\nclass ParserFactory {\n    /**\n     * Create a parser targeting the given version on a best-effort basis. The parser will generally\n     * accept code for the newest supported version, but will try to accommodate code that becomes\n     * invalid in newer versions or changes in interpretation.\n     */\n    public function createForVersion(PhpVersion $version): Parser {\n        if ($version->isHostVersion()) {\n            $lexer = new Lexer();\n        } else {\n            $lexer = new Lexer\\Emulative($version);\n        }\n        if ($version->id >= 80000) {\n            return new Php8($lexer, $version);\n        }\n        return new Php7($lexer, $version);\n    }\n\n    /**\n     * Create a parser targeting the newest version supported by this library. Code for older\n     * versions will be accepted if there have been no relevant backwards-compatibility breaks in\n     * PHP.\n     */\n    public function createForNewestSupportedVersion(): Parser {\n        return $this->createForVersion(PhpVersion::getNewestSupported());\n    }\n\n    /**\n     * Create a parser targeting the host PHP version, that is the PHP version we're currently\n     * running on. This parser will not use any token emulation.\n     */\n    public function createForHostVersion(): Parser {\n        return $this->createForVersion(PhpVersion::getHostVersion());\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/PhpVersion.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\n/**\n * A PHP version, representing only the major and minor version components.\n */\nclass PhpVersion {\n    /** @var int Version ID in PHP_VERSION_ID format */\n    public int $id;\n\n    /** @var int[] Minimum versions for builtin types */\n    private const BUILTIN_TYPE_VERSIONS = [\n        'array'    => 50100,\n        'callable' => 50400,\n        'bool'     => 70000,\n        'int'      => 70000,\n        'float'    => 70000,\n        'string'   => 70000,\n        'iterable' => 70100,\n        'void'     => 70100,\n        'object'   => 70200,\n        'null'     => 80000,\n        'false'    => 80000,\n        'mixed'    => 80000,\n        'never'    => 80100,\n        'true'     => 80200,\n    ];\n\n    private function __construct(int $id) {\n        $this->id = $id;\n    }\n\n    /**\n     * Create a PhpVersion object from major and minor version components.\n     */\n    public static function fromComponents(int $major, int $minor): self {\n        return new self($major * 10000 + $minor * 100);\n    }\n\n    /**\n     * Get the newest PHP version supported by this library. Support for this version may be partial,\n     * if it is still under development.\n     */\n    public static function getNewestSupported(): self {\n        return self::fromComponents(8, 5);\n    }\n\n    /**\n     * Get the host PHP version, that is the PHP version we're currently running on.\n     */\n    public static function getHostVersion(): self {\n        return self::fromComponents(\\PHP_MAJOR_VERSION, \\PHP_MINOR_VERSION);\n    }\n\n    /**\n     * Parse the version from a string like \"8.1\".\n     */\n    public static function fromString(string $version): self {\n        if (!preg_match('/^(\\d+)\\.(\\d+)/', $version, $matches)) {\n            throw new \\LogicException(\"Invalid PHP version \\\"$version\\\"\");\n        }\n        return self::fromComponents((int) $matches[1], (int) $matches[2]);\n    }\n\n    /**\n     * Check whether two versions are the same.\n     */\n    public function equals(PhpVersion $other): bool {\n        return $this->id === $other->id;\n    }\n\n    /**\n     * Check whether this version is greater than or equal to the argument.\n     */\n    public function newerOrEqual(PhpVersion $other): bool {\n        return $this->id >= $other->id;\n    }\n\n    /**\n     * Check whether this version is older than the argument.\n     */\n    public function older(PhpVersion $other): bool {\n        return $this->id < $other->id;\n    }\n\n    /**\n     * Check whether this is the host PHP version.\n     */\n    public function isHostVersion(): bool {\n        return $this->equals(self::getHostVersion());\n    }\n\n    /**\n     * Check whether this PHP version supports the given builtin type. Type name must be lowercase.\n     */\n    public function supportsBuiltinType(string $type): bool {\n        $minVersion = self::BUILTIN_TYPE_VERSIONS[$type] ?? null;\n        return $minVersion !== null && $this->id >= $minVersion;\n    }\n\n    /**\n     * Whether this version supports [] array literals.\n     */\n    public function supportsShortArraySyntax(): bool {\n        return $this->id >= 50400;\n    }\n\n    /**\n     * Whether this version supports [] for destructuring.\n     */\n    public function supportsShortArrayDestructuring(): bool {\n        return $this->id >= 70100;\n    }\n\n    /**\n     * Whether this version supports flexible heredoc/nowdoc.\n     */\n    public function supportsFlexibleHeredoc(): bool {\n        return $this->id >= 70300;\n    }\n\n    /**\n     * Whether this version supports trailing commas in parameter lists.\n     */\n    public function supportsTrailingCommaInParamList(): bool {\n        return $this->id >= 80000;\n    }\n\n    /**\n     * Whether this version allows \"$var =& new Obj\".\n     */\n    public function allowsAssignNewByReference(): bool {\n        return $this->id < 70000;\n    }\n\n    /**\n     * Whether this version allows invalid octals like \"08\".\n     */\n    public function allowsInvalidOctals(): bool {\n        return $this->id < 70000;\n    }\n\n    /**\n     * Whether this version allows DEL (\\x7f) to occur in identifiers.\n     */\n    public function allowsDelInIdentifiers(): bool {\n        return $this->id < 70100;\n    }\n\n    /**\n     * Whether this version supports yield in expression context without parentheses.\n     */\n    public function supportsYieldWithoutParentheses(): bool {\n        return $this->id >= 70000;\n    }\n\n    /**\n     * Whether this version supports unicode escape sequences in strings.\n     */\n    public function supportsUnicodeEscapes(): bool {\n        return $this->id >= 70000;\n    }\n\n    /*\n     * Whether this version supports attributes.\n     */\n    public function supportsAttributes(): bool {\n        return $this->id >= 80000;\n    }\n\n    public function supportsNewDereferenceWithoutParentheses(): bool {\n        return $this->id >= 80400;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter/Standard.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser\\PrettyPrinter;\n\nuse PhpParser\\Node;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Expr\\AssignOp;\nuse PhpParser\\Node\\Expr\\BinaryOp;\nuse PhpParser\\Node\\Expr\\Cast;\nuse PhpParser\\Node\\Name;\nuse PhpParser\\Node\\Scalar;\nuse PhpParser\\Node\\Scalar\\MagicConst;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\PrettyPrinterAbstract;\n\nclass Standard extends PrettyPrinterAbstract {\n    // Special nodes\n\n    protected function pParam(Node\\Param $node): string {\n        return $this->pAttrGroups($node->attrGroups, $this->phpVersion->supportsAttributes())\n             . $this->pModifiers($node->flags)\n             . ($node->type ? $this->p($node->type) . ' ' : '')\n             . ($node->byRef ? '&' : '')\n             . ($node->variadic ? '...' : '')\n             . $this->p($node->var)\n             . ($node->default ? ' = ' . $this->p($node->default) : '')\n             . ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : '');\n    }\n\n    protected function pArg(Node\\Arg $node): string {\n        return ($node->name ? $node->name->toString() . ': ' : '')\n             . ($node->byRef ? '&' : '') . ($node->unpack ? '...' : '')\n             . $this->p($node->value);\n    }\n\n    protected function pVariadicPlaceholder(Node\\VariadicPlaceholder $node): string {\n        return '...';\n    }\n\n    protected function pArgPlaceholder(Node\\ArgPlaceholder $node): string {\n        return ($node->name ? $node->name->toString() . ': ' : '') . '?';\n    }\n\n    protected function pConst(Node\\Const_ $node): string {\n        return $node->name . ' = ' . $this->p($node->value);\n    }\n\n    protected function pNullableType(Node\\NullableType $node): string {\n        return '?' . $this->p($node->type);\n    }\n\n    protected function pUnionType(Node\\UnionType $node): string {\n        $types = [];\n        foreach ($node->types as $typeNode) {\n            if ($typeNode instanceof Node\\IntersectionType) {\n                $types[] = '('. $this->p($typeNode) . ')';\n                continue;\n            }\n            $types[] = $this->p($typeNode);\n        }\n        return implode('|', $types);\n    }\n\n    protected function pIntersectionType(Node\\IntersectionType $node): string {\n        return $this->pImplode($node->types, '&');\n    }\n\n    protected function pIdentifier(Node\\Identifier $node): string {\n        return $node->name;\n    }\n\n    protected function pVarLikeIdentifier(Node\\VarLikeIdentifier $node): string {\n        return '$' . $node->name;\n    }\n\n    protected function pAttribute(Node\\Attribute $node): string {\n        return $this->p($node->name)\n             . ($node->args ? '(' . $this->pCommaSeparated($node->args) . ')' : '');\n    }\n\n    protected function pAttributeGroup(Node\\AttributeGroup $node): string {\n        return '#[' . $this->pCommaSeparated($node->attrs) . ']';\n    }\n\n    // Names\n\n    protected function pName(Name $node): string {\n        return $node->name;\n    }\n\n    protected function pName_FullyQualified(Name\\FullyQualified $node): string {\n        return '\\\\' . $node->name;\n    }\n\n    protected function pName_Relative(Name\\Relative $node): string {\n        return 'namespace\\\\' . $node->name;\n    }\n\n    // Magic Constants\n\n    protected function pScalar_MagicConst_Class(MagicConst\\Class_ $node): string {\n        return '__CLASS__';\n    }\n\n    protected function pScalar_MagicConst_Dir(MagicConst\\Dir $node): string {\n        return '__DIR__';\n    }\n\n    protected function pScalar_MagicConst_File(MagicConst\\File $node): string {\n        return '__FILE__';\n    }\n\n    protected function pScalar_MagicConst_Function(MagicConst\\Function_ $node): string {\n        return '__FUNCTION__';\n    }\n\n    protected function pScalar_MagicConst_Line(MagicConst\\Line $node): string {\n        return '__LINE__';\n    }\n\n    protected function pScalar_MagicConst_Method(MagicConst\\Method $node): string {\n        return '__METHOD__';\n    }\n\n    protected function pScalar_MagicConst_Namespace(MagicConst\\Namespace_ $node): string {\n        return '__NAMESPACE__';\n    }\n\n    protected function pScalar_MagicConst_Trait(MagicConst\\Trait_ $node): string {\n        return '__TRAIT__';\n    }\n\n    protected function pScalar_MagicConst_Property(MagicConst\\Property $node): string {\n        return '__PROPERTY__';\n    }\n\n    // Scalars\n\n    private function indentString(string $str): string {\n        return str_replace(\"\\n\", $this->nl, $str);\n    }\n\n    protected function pScalar_String(Scalar\\String_ $node): string {\n        $kind = $node->getAttribute('kind', Scalar\\String_::KIND_SINGLE_QUOTED);\n        switch ($kind) {\n            case Scalar\\String_::KIND_NOWDOC:\n                $label = $node->getAttribute('docLabel');\n                if ($label && !$this->containsEndLabel($node->value, $label)) {\n                    $shouldIdent = $this->phpVersion->supportsFlexibleHeredoc();\n                    $nl = $shouldIdent ? $this->nl : $this->newline;\n                    if ($node->value === '') {\n                        return \"<<<'$label'$nl$label{$this->docStringEndToken}\";\n                    }\n\n                    // Make sure trailing \\r is not combined with following \\n into CRLF.\n                    if ($node->value[strlen($node->value) - 1] !== \"\\r\") {\n                        $value = $shouldIdent ? $this->indentString($node->value) : $node->value;\n                        return \"<<<'$label'$nl$value$nl$label{$this->docStringEndToken}\";\n                    }\n                }\n                /* break missing intentionally */\n                // no break\n            case Scalar\\String_::KIND_SINGLE_QUOTED:\n                return $this->pSingleQuotedString($node->value);\n            case Scalar\\String_::KIND_HEREDOC:\n                $label = $node->getAttribute('docLabel');\n                $escaped = $this->escapeString($node->value, null);\n                if ($label && !$this->containsEndLabel($escaped, $label)) {\n                    $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline;\n                    if ($escaped === '') {\n                        return \"<<<$label$nl$label{$this->docStringEndToken}\";\n                    }\n\n                    return \"<<<$label$nl$escaped$nl$label{$this->docStringEndToken}\";\n                }\n                /* break missing intentionally */\n                // no break\n            case Scalar\\String_::KIND_DOUBLE_QUOTED:\n                return '\"' . $this->escapeString($node->value, '\"') . '\"';\n        }\n        throw new \\Exception('Invalid string kind');\n    }\n\n    protected function pScalar_InterpolatedString(Scalar\\InterpolatedString $node): string {\n        if ($node->getAttribute('kind') === Scalar\\String_::KIND_HEREDOC) {\n            $label = $node->getAttribute('docLabel');\n            if ($label && !$this->encapsedContainsEndLabel($node->parts, $label)) {\n                $nl = $this->phpVersion->supportsFlexibleHeredoc() ? $this->nl : $this->newline;\n                if (count($node->parts) === 1\n                    && $node->parts[0] instanceof Node\\InterpolatedStringPart\n                    && $node->parts[0]->value === ''\n                ) {\n                    return \"<<<$label$nl$label{$this->docStringEndToken}\";\n                }\n\n                return \"<<<$label$nl\" . $this->pEncapsList($node->parts, null)\n                     . \"$nl$label{$this->docStringEndToken}\";\n            }\n        }\n        return '\"' . $this->pEncapsList($node->parts, '\"') . '\"';\n    }\n\n    protected function pScalar_Int(Scalar\\Int_ $node): string {\n        if ($node->getAttribute('shouldPrintRawValue') === true) {\n            return $node->getAttribute('rawValue');\n        }\n\n        if ($node->value === -\\PHP_INT_MAX - 1) {\n            // PHP_INT_MIN cannot be represented as a literal,\n            // because the sign is not part of the literal\n            return '(-' . \\PHP_INT_MAX . '-1)';\n        }\n\n        $kind = $node->getAttribute('kind', Scalar\\Int_::KIND_DEC);\n\n        if (Scalar\\Int_::KIND_DEC === $kind) {\n            return (string) $node->value;\n        }\n\n        if ($node->value < 0) {\n            $sign = '-';\n            $str = (string) -$node->value;\n        } else {\n            $sign = '';\n            $str = (string) $node->value;\n        }\n        switch ($kind) {\n            case Scalar\\Int_::KIND_BIN:\n                return $sign . '0b' . base_convert($str, 10, 2);\n            case Scalar\\Int_::KIND_OCT:\n                return $sign . '0' . base_convert($str, 10, 8);\n            case Scalar\\Int_::KIND_HEX:\n                return $sign . '0x' . base_convert($str, 10, 16);\n        }\n        throw new \\Exception('Invalid number kind');\n    }\n\n    protected function pScalar_Float(Scalar\\Float_ $node): string {\n        if (!is_finite($node->value)) {\n            if ($node->value === \\INF) {\n                return '1.0E+1000';\n            }\n            if ($node->value === -\\INF) {\n                return '-1.0E+1000';\n            } else {\n                return '\\NAN';\n            }\n        }\n\n        // Try to find a short full-precision representation\n        $stringValue = sprintf('%.16G', $node->value);\n        if ($node->value !== (float) $stringValue) {\n            $stringValue = sprintf('%.17G', $node->value);\n        }\n\n        // %G is locale dependent and there exists no locale-independent alternative. We don't want\n        // mess with switching locales here, so let's assume that a comma is the only non-standard\n        // decimal separator we may encounter...\n        $stringValue = str_replace(',', '.', $stringValue);\n\n        // ensure that number is really printed as float\n        return preg_match('/^-?[0-9]+$/', $stringValue) ? $stringValue . '.0' : $stringValue;\n    }\n\n    // Assignments\n\n    protected function pExpr_Assign(Expr\\Assign $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\Assign::class, $this->p($node->var) . ' = ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignRef(Expr\\AssignRef $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\AssignRef::class, $this->p($node->var) . ' =& ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Plus(AssignOp\\Plus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Plus::class, $this->p($node->var) . ' += ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Minus(AssignOp\\Minus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Minus::class, $this->p($node->var) . ' -= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Mul(AssignOp\\Mul $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Mul::class, $this->p($node->var) . ' *= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Div(AssignOp\\Div $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Div::class, $this->p($node->var) . ' /= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Concat(AssignOp\\Concat $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Concat::class, $this->p($node->var) . ' .= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Mod(AssignOp\\Mod $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Mod::class, $this->p($node->var) . ' %= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_BitwiseAnd(AssignOp\\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\BitwiseAnd::class, $this->p($node->var) . ' &= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_BitwiseOr(AssignOp\\BitwiseOr $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\BitwiseOr::class, $this->p($node->var) . ' |= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_BitwiseXor(AssignOp\\BitwiseXor $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\BitwiseXor::class, $this->p($node->var) . ' ^= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_ShiftLeft(AssignOp\\ShiftLeft $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\ShiftLeft::class, $this->p($node->var) . ' <<= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_ShiftRight(AssignOp\\ShiftRight $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\ShiftRight::class, $this->p($node->var) . ' >>= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Pow(AssignOp\\Pow $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Pow::class, $this->p($node->var) . ' **= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_AssignOp_Coalesce(AssignOp\\Coalesce $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(AssignOp\\Coalesce::class, $this->p($node->var) . ' ??= ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    // Binary expressions\n\n    protected function pExpr_BinaryOp_Plus(BinaryOp\\Plus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Plus::class, $node->left, ' + ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Minus(BinaryOp\\Minus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Minus::class, $node->left, ' - ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Mul(BinaryOp\\Mul $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Mul::class, $node->left, ' * ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Div(BinaryOp\\Div $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Div::class, $node->left, ' / ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Concat(BinaryOp\\Concat $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Concat::class, $node->left, ' . ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Mod(BinaryOp\\Mod $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Mod::class, $node->left, ' % ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_BooleanAnd(BinaryOp\\BooleanAnd $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\BooleanAnd::class, $node->left, ' && ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_BooleanOr(BinaryOp\\BooleanOr $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\BooleanOr::class, $node->left, ' || ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_BitwiseAnd(BinaryOp\\BitwiseAnd $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\BitwiseAnd::class, $node->left, ' & ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_BitwiseOr(BinaryOp\\BitwiseOr $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\BitwiseOr::class, $node->left, ' | ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_BitwiseXor(BinaryOp\\BitwiseXor $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\BitwiseXor::class, $node->left, ' ^ ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_ShiftLeft(BinaryOp\\ShiftLeft $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\ShiftLeft::class, $node->left, ' << ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_ShiftRight(BinaryOp\\ShiftRight $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\ShiftRight::class, $node->left, ' >> ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Pow(BinaryOp\\Pow $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Pow::class, $node->left, ' ** ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_LogicalAnd(BinaryOp\\LogicalAnd $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\LogicalAnd::class, $node->left, ' and ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_LogicalOr(BinaryOp\\LogicalOr $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\LogicalOr::class, $node->left, ' or ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_LogicalXor(BinaryOp\\LogicalXor $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\LogicalXor::class, $node->left, ' xor ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Equal(BinaryOp\\Equal $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Equal::class, $node->left, ' == ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_NotEqual(BinaryOp\\NotEqual $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\NotEqual::class, $node->left, ' != ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Identical(BinaryOp\\Identical $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Identical::class, $node->left, ' === ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_NotIdentical(BinaryOp\\NotIdentical $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\NotIdentical::class, $node->left, ' !== ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Spaceship(BinaryOp\\Spaceship $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Spaceship::class, $node->left, ' <=> ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Greater(BinaryOp\\Greater $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Greater::class, $node->left, ' > ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_GreaterOrEqual(BinaryOp\\GreaterOrEqual $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\GreaterOrEqual::class, $node->left, ' >= ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Smaller(BinaryOp\\Smaller $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Smaller::class, $node->left, ' < ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_SmallerOrEqual(BinaryOp\\SmallerOrEqual $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\SmallerOrEqual::class, $node->left, ' <= ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Coalesce(BinaryOp\\Coalesce $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pInfixOp(BinaryOp\\Coalesce::class, $node->left, ' ?? ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BinaryOp_Pipe(BinaryOp\\Pipe $node, int $precedence, int $lhsPrecedence): string {\n        if ($node->right instanceof Expr\\ArrowFunction) {\n            // Force parentheses around arrow functions.\n            $lhsPrecedence = $this->precedenceMap[Expr\\ArrowFunction::class][0];\n        }\n        return $this->pInfixOp(BinaryOp\\Pipe::class, $node->left, ' |> ', $node->right, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Instanceof(Expr\\Instanceof_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPostfixOp(\n            Expr\\Instanceof_::class, $node->expr,\n            ' instanceof ' . $this->pNewOperand($node->class),\n            $precedence, $lhsPrecedence);\n    }\n\n    // Unary expressions\n\n    protected function pExpr_BooleanNot(Expr\\BooleanNot $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\BooleanNot::class, '!', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_BitwiseNot(Expr\\BitwiseNot $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\BitwiseNot::class, '~', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_UnaryMinus(Expr\\UnaryMinus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\UnaryMinus::class, '-', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_UnaryPlus(Expr\\UnaryPlus $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\UnaryPlus::class, '+', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_PreInc(Expr\\PreInc $node): string {\n        return '++' . $this->p($node->var);\n    }\n\n    protected function pExpr_PreDec(Expr\\PreDec $node): string {\n        return '--' . $this->p($node->var);\n    }\n\n    protected function pExpr_PostInc(Expr\\PostInc $node): string {\n        return $this->p($node->var) . '++';\n    }\n\n    protected function pExpr_PostDec(Expr\\PostDec $node): string {\n        return $this->p($node->var) . '--';\n    }\n\n    protected function pExpr_ErrorSuppress(Expr\\ErrorSuppress $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\ErrorSuppress::class, '@', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_YieldFrom(Expr\\YieldFrom $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\YieldFrom::class, 'yield from ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Print(Expr\\Print_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\Print_::class, 'print ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    // Casts\n\n    protected function pExpr_Cast_Int(Cast\\Int_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Int_::class, '(int) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Double(Cast\\Double $node, int $precedence, int $lhsPrecedence): string {\n        $kind = $node->getAttribute('kind', Cast\\Double::KIND_DOUBLE);\n        if ($kind === Cast\\Double::KIND_DOUBLE) {\n            $cast = '(double)';\n        } elseif ($kind === Cast\\Double::KIND_FLOAT) {\n            $cast = '(float)';\n        } else {\n            assert($kind === Cast\\Double::KIND_REAL);\n            $cast = '(real)';\n        }\n        return $this->pPrefixOp(Cast\\Double::class, $cast . ' ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_String(Cast\\String_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\String_::class, '(string) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Array(Cast\\Array_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Array_::class, '(array) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Object(Cast\\Object_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Object_::class, '(object) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Bool(Cast\\Bool_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Bool_::class, '(bool) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Unset(Cast\\Unset_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Unset_::class, '(unset) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Cast_Void(Cast\\Void_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Cast\\Void_::class, '(void) ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    // Function calls and similar constructs\n\n    protected function pExpr_FuncCall(Expr\\FuncCall $node): string {\n        return $this->pCallLhs($node->name)\n             . '(' . $this->pMaybeMultiline($node->args) . ')';\n    }\n\n    protected function pExpr_MethodCall(Expr\\MethodCall $node): string {\n        return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name)\n             . '(' . $this->pMaybeMultiline($node->args) . ')';\n    }\n\n    protected function pExpr_NullsafeMethodCall(Expr\\NullsafeMethodCall $node): string {\n        return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name)\n            . '(' . $this->pMaybeMultiline($node->args) . ')';\n    }\n\n    protected function pExpr_StaticCall(Expr\\StaticCall $node): string {\n        return $this->pStaticDereferenceLhs($node->class) . '::'\n             . ($node->name instanceof Expr\n                ? ($node->name instanceof Expr\\Variable\n                   ? $this->p($node->name)\n                   : '{' . $this->p($node->name) . '}')\n                : $node->name)\n             . '(' . $this->pMaybeMultiline($node->args) . ')';\n    }\n\n    protected function pExpr_Empty(Expr\\Empty_ $node): string {\n        return 'empty(' . $this->p($node->expr) . ')';\n    }\n\n    protected function pExpr_Isset(Expr\\Isset_ $node): string {\n        return 'isset(' . $this->pCommaSeparated($node->vars) . ')';\n    }\n\n    protected function pExpr_Eval(Expr\\Eval_ $node): string {\n        return 'eval(' . $this->p($node->expr) . ')';\n    }\n\n    protected function pExpr_Include(Expr\\Include_ $node, int $precedence, int $lhsPrecedence): string {\n        static $map = [\n            Expr\\Include_::TYPE_INCLUDE      => 'include',\n            Expr\\Include_::TYPE_INCLUDE_ONCE => 'include_once',\n            Expr\\Include_::TYPE_REQUIRE      => 'require',\n            Expr\\Include_::TYPE_REQUIRE_ONCE => 'require_once',\n        ];\n\n        return $this->pPrefixOp(Expr\\Include_::class, $map[$node->type] . ' ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_List(Expr\\List_ $node): string {\n        $syntax = $node->getAttribute('kind',\n            $this->phpVersion->supportsShortArrayDestructuring() ? Expr\\List_::KIND_ARRAY : Expr\\List_::KIND_LIST);\n        if ($syntax === Expr\\List_::KIND_ARRAY) {\n            return '[' . $this->pMaybeMultiline($node->items, true) . ']';\n        } else {\n            return 'list(' . $this->pMaybeMultiline($node->items, true) . ')';\n        }\n    }\n\n    // Other\n\n    protected function pExpr_Error(Expr\\Error $node): string {\n        throw new \\LogicException('Cannot pretty-print AST with Error nodes');\n    }\n\n    protected function pExpr_Variable(Expr\\Variable $node): string {\n        if ($node->name instanceof Expr) {\n            return '${' . $this->p($node->name) . '}';\n        } else {\n            return '$' . $node->name;\n        }\n    }\n\n    protected function pExpr_Array(Expr\\Array_ $node): string {\n        $syntax = $node->getAttribute('kind',\n            $this->shortArraySyntax ? Expr\\Array_::KIND_SHORT : Expr\\Array_::KIND_LONG);\n        if ($syntax === Expr\\Array_::KIND_SHORT) {\n            return '[' . $this->pMaybeMultiline($node->items, true) . ']';\n        } else {\n            return 'array(' . $this->pMaybeMultiline($node->items, true) . ')';\n        }\n    }\n\n    protected function pKey(?Node $node): string {\n        if ($node === null) {\n            return '';\n        }\n\n        // => is not really an operator and does not typically participate in precedence resolution.\n        // However, there is an exception if yield expressions with keys are involved:\n        // [yield $a => $b] is interpreted as [(yield $a => $b)], so we need to ensure that\n        // [(yield $a) => $b] is printed with parentheses. We approximate this by lowering the LHS\n        // precedence to that of yield (which will also print unnecessary parentheses for rare low\n        // precedence unary operators like include).\n        $yieldPrecedence = $this->precedenceMap[Expr\\Yield_::class][0];\n        return $this->p($node, self::MAX_PRECEDENCE, $yieldPrecedence) . ' => ';\n    }\n\n    protected function pArrayItem(Node\\ArrayItem $node): string {\n        return $this->pKey($node->key)\n             . ($node->byRef ? '&' : '')\n             . ($node->unpack ? '...' : '')\n             . $this->p($node->value);\n    }\n\n    protected function pExpr_ArrayDimFetch(Expr\\ArrayDimFetch $node): string {\n        return $this->pDereferenceLhs($node->var)\n             . '[' . (null !== $node->dim ? $this->p($node->dim) : '') . ']';\n    }\n\n    protected function pExpr_ConstFetch(Expr\\ConstFetch $node): string {\n        return $this->p($node->name);\n    }\n\n    protected function pExpr_ClassConstFetch(Expr\\ClassConstFetch $node): string {\n        return $this->pStaticDereferenceLhs($node->class) . '::' . $this->pObjectProperty($node->name);\n    }\n\n    protected function pExpr_PropertyFetch(Expr\\PropertyFetch $node): string {\n        return $this->pDereferenceLhs($node->var) . '->' . $this->pObjectProperty($node->name);\n    }\n\n    protected function pExpr_NullsafePropertyFetch(Expr\\NullsafePropertyFetch $node): string {\n        return $this->pDereferenceLhs($node->var) . '?->' . $this->pObjectProperty($node->name);\n    }\n\n    protected function pExpr_StaticPropertyFetch(Expr\\StaticPropertyFetch $node): string {\n        return $this->pStaticDereferenceLhs($node->class) . '::$' . $this->pObjectProperty($node->name);\n    }\n\n    protected function pExpr_ShellExec(Expr\\ShellExec $node): string {\n        return '`' . $this->pEncapsList($node->parts, '`') . '`';\n    }\n\n    protected function pExpr_Closure(Expr\\Closure $node): string {\n        return $this->pAttrGroups($node->attrGroups, true)\n             . $this->pStatic($node->static)\n             . 'function ' . ($node->byRef ? '&' : '')\n             . '(' . $this->pParams($node->params) . ')'\n             . (!empty($node->uses) ? ' use (' . $this->pCommaSeparated($node->uses) . ')' : '')\n             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')\n             . ' {' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pExpr_Match(Expr\\Match_ $node): string {\n        return 'match (' . $this->p($node->cond) . ') {'\n            . $this->pCommaSeparatedMultiline($node->arms, true)\n            . $this->nl\n            . '}';\n    }\n\n    protected function pMatchArm(Node\\MatchArm $node): string {\n        $result = '';\n        if ($node->conds) {\n            for ($i = 0, $c = \\count($node->conds); $i + 1 < $c; $i++) {\n                $result .= $this->p($node->conds[$i]) . ', ';\n            }\n            $result .= $this->pKey($node->conds[$i]);\n        } else {\n            $result = 'default => ';\n        }\n        return $result . $this->p($node->body);\n    }\n\n    protected function pExpr_ArrowFunction(Expr\\ArrowFunction $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(\n            Expr\\ArrowFunction::class,\n            $this->pAttrGroups($node->attrGroups, true)\n            . $this->pStatic($node->static)\n            . 'fn' . ($node->byRef ? '&' : '')\n            . '(' . $this->pParams($node->params) . ')'\n            . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')\n            . ' => ',\n            $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pClosureUse(Node\\ClosureUse $node): string {\n        return ($node->byRef ? '&' : '') . $this->p($node->var);\n    }\n\n    protected function pExpr_New(Expr\\New_ $node): string {\n        if ($node->class instanceof Stmt\\Class_) {\n            $args = $node->args ? '(' . $this->pMaybeMultiline($node->args) . ')' : '';\n            return 'new ' . $this->pClassCommon($node->class, $args);\n        }\n        return 'new ' . $this->pNewOperand($node->class)\n            . '(' . $this->pMaybeMultiline($node->args) . ')';\n    }\n\n    protected function pExpr_Clone(Expr\\Clone_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\Clone_::class, 'clone ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Ternary(Expr\\Ternary $node, int $precedence, int $lhsPrecedence): string {\n        // a bit of cheating: we treat the ternary as a binary op where the ?...: part is the operator.\n        // this is okay because the part between ? and : never needs parentheses.\n        return $this->pInfixOp(Expr\\Ternary::class,\n            $node->cond, ' ?' . (null !== $node->if ? ' ' . $this->p($node->if) . ' ' : '') . ': ', $node->else,\n            $precedence, $lhsPrecedence\n        );\n    }\n\n    protected function pExpr_Exit(Expr\\Exit_ $node): string {\n        $kind = $node->getAttribute('kind', Expr\\Exit_::KIND_DIE);\n        return ($kind === Expr\\Exit_::KIND_EXIT ? 'exit' : 'die')\n             . (null !== $node->expr ? '(' . $this->p($node->expr) . ')' : '');\n    }\n\n    protected function pExpr_Throw(Expr\\Throw_ $node, int $precedence, int $lhsPrecedence): string {\n        return $this->pPrefixOp(Expr\\Throw_::class, 'throw ', $node->expr, $precedence, $lhsPrecedence);\n    }\n\n    protected function pExpr_Yield(Expr\\Yield_ $node, int $precedence, int $lhsPrecedence): string {\n        if ($node->value === null) {\n            $opPrecedence = $this->precedenceMap[Expr\\Yield_::class][0];\n            return $opPrecedence >= $lhsPrecedence ? '(yield)' : 'yield';\n        } else {\n            if (!$this->phpVersion->supportsYieldWithoutParentheses()) {\n                return '(yield ' . $this->pKey($node->key) . $this->p($node->value) . ')';\n            }\n            return $this->pPrefixOp(\n                Expr\\Yield_::class, 'yield ' . $this->pKey($node->key),\n                $node->value, $precedence, $lhsPrecedence);\n        }\n    }\n\n    // Declarations\n\n    protected function pStmt_Namespace(Stmt\\Namespace_ $node): string {\n        if ($this->canUseSemicolonNamespaces) {\n            return 'namespace ' . $this->p($node->name) . ';'\n                 . $this->nl . $this->pStmts($node->stmts, false);\n        } else {\n            return 'namespace' . (null !== $node->name ? ' ' . $this->p($node->name) : '')\n                 . ' {' . $this->pStmts($node->stmts) . $this->nl . '}';\n        }\n    }\n\n    protected function pStmt_Use(Stmt\\Use_ $node): string {\n        return 'use ' . $this->pUseType($node->type)\n             . $this->pCommaSeparated($node->uses) . ';';\n    }\n\n    protected function pStmt_GroupUse(Stmt\\GroupUse $node): string {\n        return 'use ' . $this->pUseType($node->type) . $this->pName($node->prefix)\n             . '\\{' . $this->pCommaSeparated($node->uses) . '};';\n    }\n\n    protected function pUseItem(Node\\UseItem $node): string {\n        return $this->pUseType($node->type) . $this->p($node->name)\n             . (null !== $node->alias ? ' as ' . $node->alias : '');\n    }\n\n    protected function pUseType(int $type): string {\n        return $type === Stmt\\Use_::TYPE_FUNCTION ? 'function '\n            : ($type === Stmt\\Use_::TYPE_CONSTANT ? 'const ' : '');\n    }\n\n    protected function pStmt_Interface(Stmt\\Interface_ $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . 'interface ' . $node->name\n             . (!empty($node->extends) ? ' extends ' . $this->pCommaSeparated($node->extends) : '')\n             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Enum(Stmt\\Enum_ $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . 'enum ' . $node->name\n             . ($node->scalarType ? ' : ' . $this->p($node->scalarType) : '')\n             . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')\n             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Class(Stmt\\Class_ $node): string {\n        return $this->pClassCommon($node, ' ' . $node->name);\n    }\n\n    protected function pStmt_Trait(Stmt\\Trait_ $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . 'trait ' . $node->name\n             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_EnumCase(Stmt\\EnumCase $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . 'case ' . $node->name\n             . ($node->expr ? ' = ' . $this->p($node->expr) : '')\n             . ';';\n    }\n\n    protected function pStmt_TraitUse(Stmt\\TraitUse $node): string {\n        return 'use ' . $this->pCommaSeparated($node->traits)\n             . (empty($node->adaptations)\n                ? ';'\n                : ' {' . $this->pStmts($node->adaptations) . $this->nl . '}');\n    }\n\n    protected function pStmt_TraitUseAdaptation_Precedence(Stmt\\TraitUseAdaptation\\Precedence $node): string {\n        return $this->p($node->trait) . '::' . $node->method\n             . ' insteadof ' . $this->pCommaSeparated($node->insteadof) . ';';\n    }\n\n    protected function pStmt_TraitUseAdaptation_Alias(Stmt\\TraitUseAdaptation\\Alias $node): string {\n        return (null !== $node->trait ? $this->p($node->trait) . '::' : '')\n             . $node->method . ' as'\n             . (null !== $node->newModifier ? ' ' . rtrim($this->pModifiers($node->newModifier), ' ') : '')\n             . (null !== $node->newName ? ' ' . $node->newName : '')\n             . ';';\n    }\n\n    protected function pStmt_Property(Stmt\\Property $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n            . (0 === $node->flags ? 'var ' : $this->pModifiers($node->flags))\n            . ($node->type ? $this->p($node->type) . ' ' : '')\n            . $this->pCommaSeparated($node->props)\n            . ($node->hooks ? ' {' . $this->pStmts($node->hooks) . $this->nl . '}' : ';');\n    }\n\n    protected function pPropertyItem(Node\\PropertyItem $node): string {\n        return '$' . $node->name\n             . (null !== $node->default ? ' = ' . $this->p($node->default) : '');\n    }\n\n    protected function pPropertyHook(Node\\PropertyHook $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . $this->pModifiers($node->flags)\n             . ($node->byRef ? '&' : '') . $node->name\n             . ($node->params ? '(' . $this->pParams($node->params) . ')' : '')\n             . (\\is_array($node->body) ? ' {' . $this->pStmts($node->body) . $this->nl . '}'\n                : ($node->body !== null ? ' => ' . $this->p($node->body) : '') . ';');\n    }\n\n    protected function pStmt_ClassMethod(Stmt\\ClassMethod $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . $this->pModifiers($node->flags)\n             . 'function ' . ($node->byRef ? '&' : '') . $node->name\n             . '(' . $this->pParams($node->params) . ')'\n             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')\n             . (null !== $node->stmts\n                ? $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}'\n                : ';');\n    }\n\n    protected function pStmt_ClassConst(Stmt\\ClassConst $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . $this->pModifiers($node->flags)\n             . 'const '\n             . (null !== $node->type ? $this->p($node->type) . ' ' : '')\n             . $this->pCommaSeparated($node->consts) . ';';\n    }\n\n    protected function pStmt_Function(Stmt\\Function_ $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n             . 'function ' . ($node->byRef ? '&' : '') . $node->name\n             . '(' . $this->pParams($node->params) . ')'\n             . (null !== $node->returnType ? ': ' . $this->p($node->returnType) : '')\n             . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Const(Stmt\\Const_ $node): string {\n        return $this->pAttrGroups($node->attrGroups)\n            . 'const '\n            . $this->pCommaSeparated($node->consts) . ';';\n    }\n\n    protected function pStmt_Declare(Stmt\\Declare_ $node): string {\n        return 'declare (' . $this->pCommaSeparated($node->declares) . ')'\n             . (null !== $node->stmts ? ' {' . $this->pStmts($node->stmts) . $this->nl . '}' : ';');\n    }\n\n    protected function pDeclareItem(Node\\DeclareItem $node): string {\n        return $node->key . '=' . $this->p($node->value);\n    }\n\n    // Control flow\n\n    protected function pStmt_If(Stmt\\If_ $node): string {\n        return 'if (' . $this->p($node->cond) . ') {'\n             . $this->pStmts($node->stmts) . $this->nl . '}'\n             . ($node->elseifs ? ' ' . $this->pImplode($node->elseifs, ' ') : '')\n             . (null !== $node->else ? ' ' . $this->p($node->else) : '');\n    }\n\n    protected function pStmt_ElseIf(Stmt\\ElseIf_ $node): string {\n        return 'elseif (' . $this->p($node->cond) . ') {'\n             . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Else(Stmt\\Else_ $node): string {\n        if (\\count($node->stmts) === 1 && $node->stmts[0] instanceof Stmt\\If_) {\n            // Print as \"else if\" rather than \"else { if }\"\n            return 'else ' . $this->p($node->stmts[0]);\n        }\n        return 'else {' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_For(Stmt\\For_ $node): string {\n        return 'for ('\n             . $this->pCommaSeparated($node->init) . ';' . (!empty($node->cond) ? ' ' : '')\n             . $this->pCommaSeparated($node->cond) . ';' . (!empty($node->loop) ? ' ' : '')\n             . $this->pCommaSeparated($node->loop)\n             . ') {' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Foreach(Stmt\\Foreach_ $node): string {\n        return 'foreach (' . $this->p($node->expr) . ' as '\n             . (null !== $node->keyVar ? $this->p($node->keyVar) . ' => ' : '')\n             . ($node->byRef ? '&' : '') . $this->p($node->valueVar) . ') {'\n             . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_While(Stmt\\While_ $node): string {\n        return 'while (' . $this->p($node->cond) . ') {'\n             . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Do(Stmt\\Do_ $node): string {\n        return 'do {' . $this->pStmts($node->stmts) . $this->nl\n             . '} while (' . $this->p($node->cond) . ');';\n    }\n\n    protected function pStmt_Switch(Stmt\\Switch_ $node): string {\n        return 'switch (' . $this->p($node->cond) . ') {'\n             . $this->pStmts($node->cases) . $this->nl . '}';\n    }\n\n    protected function pStmt_Case(Stmt\\Case_ $node): string {\n        return (null !== $node->cond ? 'case ' . $this->p($node->cond) : 'default') . ':'\n             . $this->pStmts($node->stmts);\n    }\n\n    protected function pStmt_TryCatch(Stmt\\TryCatch $node): string {\n        return 'try {' . $this->pStmts($node->stmts) . $this->nl . '}'\n             . ($node->catches ? ' ' . $this->pImplode($node->catches, ' ') : '')\n             . ($node->finally !== null ? ' ' . $this->p($node->finally) : '');\n    }\n\n    protected function pStmt_Catch(Stmt\\Catch_ $node): string {\n        return 'catch (' . $this->pImplode($node->types, '|')\n             . ($node->var !== null ? ' ' . $this->p($node->var) : '')\n             . ') {' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Finally(Stmt\\Finally_ $node): string {\n        return 'finally {' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pStmt_Break(Stmt\\Break_ $node): string {\n        return 'break' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';\n    }\n\n    protected function pStmt_Continue(Stmt\\Continue_ $node): string {\n        return 'continue' . ($node->num !== null ? ' ' . $this->p($node->num) : '') . ';';\n    }\n\n    protected function pStmt_Return(Stmt\\Return_ $node): string {\n        return 'return' . (null !== $node->expr ? ' ' . $this->p($node->expr) : '') . ';';\n    }\n\n    protected function pStmt_Label(Stmt\\Label $node): string {\n        return $node->name . ':';\n    }\n\n    protected function pStmt_Goto(Stmt\\Goto_ $node): string {\n        return 'goto ' . $node->name . ';';\n    }\n\n    // Other\n\n    protected function pStmt_Expression(Stmt\\Expression $node): string {\n        return $this->p($node->expr) . ';';\n    }\n\n    protected function pStmt_Echo(Stmt\\Echo_ $node): string {\n        return 'echo ' . $this->pCommaSeparated($node->exprs) . ';';\n    }\n\n    protected function pStmt_Static(Stmt\\Static_ $node): string {\n        return 'static ' . $this->pCommaSeparated($node->vars) . ';';\n    }\n\n    protected function pStmt_Global(Stmt\\Global_ $node): string {\n        return 'global ' . $this->pCommaSeparated($node->vars) . ';';\n    }\n\n    protected function pStaticVar(Node\\StaticVar $node): string {\n        return $this->p($node->var)\n             . (null !== $node->default ? ' = ' . $this->p($node->default) : '');\n    }\n\n    protected function pStmt_Unset(Stmt\\Unset_ $node): string {\n        return 'unset(' . $this->pCommaSeparated($node->vars) . ');';\n    }\n\n    protected function pStmt_InlineHTML(Stmt\\InlineHTML $node): string {\n        $newline = $node->getAttribute('hasLeadingNewline', true) ? $this->newline : '';\n        return '?>' . $newline . $node->value . '<?php ';\n    }\n\n    protected function pStmt_HaltCompiler(Stmt\\HaltCompiler $node): string {\n        return '__halt_compiler();' . $node->remaining;\n    }\n\n    protected function pStmt_Nop(Stmt\\Nop $node): string {\n        return '';\n    }\n\n    protected function pStmt_Block(Stmt\\Block $node): string {\n        return '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    // Helpers\n\n    protected function pClassCommon(Stmt\\Class_ $node, string $afterClassToken): string {\n        return $this->pAttrGroups($node->attrGroups, $node->name === null)\n            . $this->pModifiers($node->flags)\n            . 'class' . $afterClassToken\n            . (null !== $node->extends ? ' extends ' . $this->p($node->extends) : '')\n            . (!empty($node->implements) ? ' implements ' . $this->pCommaSeparated($node->implements) : '')\n            . $this->nl . '{' . $this->pStmts($node->stmts) . $this->nl . '}';\n    }\n\n    protected function pObjectProperty(Node $node): string {\n        if ($node instanceof Expr) {\n            return '{' . $this->p($node) . '}';\n        } else {\n            assert($node instanceof Node\\Identifier);\n            return $node->name;\n        }\n    }\n\n    /** @param (Expr|Node\\InterpolatedStringPart)[] $encapsList */\n    protected function pEncapsList(array $encapsList, ?string $quote): string {\n        $return = '';\n        foreach ($encapsList as $element) {\n            if ($element instanceof Node\\InterpolatedStringPart) {\n                $return .= $this->escapeString($element->value, $quote);\n            } else {\n                $return .= '{' . $this->p($element) . '}';\n            }\n        }\n\n        return $return;\n    }\n\n    protected function pSingleQuotedString(string $string): string {\n        // It is idiomatic to only escape backslashes when necessary, i.e. when followed by ', \\ or\n        // the end of the string ('Foo\\Bar' instead of 'Foo\\\\Bar'). However, we also don't want to\n        // produce an odd number of backslashes, so '\\\\\\\\a' should not get rendered as '\\\\\\a', even\n        // though that would be legal.\n        $regex = '/\\'|\\\\\\\\(?=[\\'\\\\\\\\]|$)|(?<=\\\\\\\\)\\\\\\\\/';\n        return '\\'' . preg_replace($regex, '\\\\\\\\$0', $string) . '\\'';\n    }\n\n    protected function escapeString(string $string, ?string $quote): string {\n        if (null === $quote) {\n            // For doc strings, don't escape newlines\n            $escaped = addcslashes($string, \"\\t\\f\\v$\\\\\");\n            // But do escape isolated \\r. Combined with the terminating newline, it might get\n            // interpreted as \\r\\n and dropped from the string contents.\n            $escaped = preg_replace('/\\r(?!\\n)/', '\\\\r', $escaped);\n            if ($this->phpVersion->supportsFlexibleHeredoc()) {\n                $escaped = $this->indentString($escaped);\n            }\n        } else {\n            $escaped = addcslashes($string, \"\\n\\r\\t\\f\\v$\" . $quote . \"\\\\\");\n        }\n\n        // Escape control characters and non-UTF-8 characters.\n        // Regex based on https://stackoverflow.com/a/11709412/385378.\n        $regex = '/(\n              [\\x00-\\x08\\x0E-\\x1F] # Control characters\n            | [\\xC0-\\xC1] # Invalid UTF-8 Bytes\n            | [\\xF5-\\xFF] # Invalid UTF-8 Bytes\n            | \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point\n            | \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point\n            | [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start\n            | [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start\n            | [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start\n            | (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle\n            | (?<![\\xC2-\\xDF]|[\\xE0-\\xEF]|[\\xE0-\\xEF][\\x80-\\xBF]|[\\xF0-\\xF4]|[\\xF0-\\xF4][\\x80-\\xBF]|[\\xF0-\\xF4][\\x80-\\xBF]{2})[\\x80-\\xBF] # Overlong Sequence\n            | (?<=[\\xE0-\\xEF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 3 byte sequence\n            | (?<=[\\xF0-\\xF4])[\\x80-\\xBF](?![\\x80-\\xBF]{2}) # Short 4 byte sequence\n            | (?<=[\\xF0-\\xF4][\\x80-\\xBF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 4 byte sequence (2)\n        )/x';\n        return preg_replace_callback($regex, function ($matches): string {\n            assert(strlen($matches[0]) === 1);\n            $hex = dechex(ord($matches[0]));\n            return '\\\\x' . str_pad($hex, 2, '0', \\STR_PAD_LEFT);\n        }, $escaped);\n    }\n\n    protected function containsEndLabel(string $string, string $label, bool $atStart = true): bool {\n        $start = $atStart ? '(?:^|[\\r\\n])[ \\t]*' : '[\\r\\n][ \\t]*';\n        return false !== strpos($string, $label)\n            && preg_match('/' . $start . $label . '(?:$|[^_A-Za-z0-9\\x80-\\xff])/', $string);\n    }\n\n    /** @param (Expr|Node\\InterpolatedStringPart)[] $parts */\n    protected function encapsedContainsEndLabel(array $parts, string $label): bool {\n        foreach ($parts as $i => $part) {\n            if ($part instanceof Node\\InterpolatedStringPart\n                && $this->containsEndLabel($this->escapeString($part->value, null), $label, $i === 0)\n            ) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    protected function pDereferenceLhs(Node $node): string {\n        if (!$this->dereferenceLhsRequiresParens($node)) {\n            return $this->p($node);\n        } else {\n            return '(' . $this->p($node) . ')';\n        }\n    }\n\n    protected function pStaticDereferenceLhs(Node $node): string {\n        if (!$this->staticDereferenceLhsRequiresParens($node)) {\n            return $this->p($node);\n        } else {\n            return '(' . $this->p($node) . ')';\n        }\n    }\n\n    protected function pCallLhs(Node $node): string {\n        if (!$this->callLhsRequiresParens($node)) {\n            return $this->p($node);\n        } else {\n            return '(' . $this->p($node) . ')';\n        }\n    }\n\n    protected function pNewOperand(Node $node): string {\n        if (!$this->newOperandRequiresParens($node)) {\n            return $this->p($node);\n        } else {\n            return '(' . $this->p($node) . ')';\n        }\n    }\n\n    /**\n     * @param Node[] $nodes\n     */\n    protected function hasNodeWithComments(array $nodes): bool {\n        foreach ($nodes as $node) {\n            if ($node && $node->getComments()) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /** @param Node[] $nodes */\n    protected function pMaybeMultiline(array $nodes, bool $trailingComma = false): string {\n        if (!$this->hasNodeWithComments($nodes)) {\n            return $this->pCommaSeparated($nodes);\n        } else {\n            return $this->pCommaSeparatedMultiline($nodes, $trailingComma) . $this->nl;\n        }\n    }\n\n    /** @param Node\\Param[] $params\n     */\n    private function hasParamWithAttributes(array $params): bool {\n        foreach ($params as $param) {\n            if ($param->attrGroups) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /** @param Node\\Param[] $params */\n    protected function pParams(array $params): string {\n        if ($this->hasNodeWithComments($params) ||\n            ($this->hasParamWithAttributes($params) && !$this->phpVersion->supportsAttributes())\n        ) {\n            return $this->pCommaSeparatedMultiline($params, $this->phpVersion->supportsTrailingCommaInParamList()) . $this->nl;\n        }\n        return $this->pCommaSeparated($params);\n    }\n\n    /** @param Node\\AttributeGroup[] $nodes */\n    protected function pAttrGroups(array $nodes, bool $inline = false): string {\n        $result = '';\n        $sep = $inline ? ' ' : $this->nl;\n        foreach ($nodes as $node) {\n            $result .= $this->p($node) . $sep;\n        }\n\n        return $result;\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinter.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Node\\Expr;\n\ninterface PrettyPrinter {\n    /**\n     * Pretty prints an array of statements.\n     *\n     * @param Node[] $stmts Array of statements\n     *\n     * @return string Pretty printed statements\n     */\n    public function prettyPrint(array $stmts): string;\n\n    /**\n     * Pretty prints an expression.\n     *\n     * @param Expr $node Expression node\n     *\n     * @return string Pretty printed node\n     */\n    public function prettyPrintExpr(Expr $node): string;\n\n    /**\n     * Pretty prints a file of statements (includes the opening <?php tag if it is required).\n     *\n     * @param Node[] $stmts Array of statements\n     *\n     * @return string Pretty printed statements\n     */\n    public function prettyPrintFile(array $stmts): string;\n\n    /**\n     * Perform a format-preserving pretty print of an AST.\n     *\n     * The format preservation is best effort. For some changes to the AST the formatting will not\n     * be preserved (at least not locally).\n     *\n     * In order to use this method a number of prerequisites must be satisfied:\n     *  * The startTokenPos and endTokenPos attributes in the lexer must be enabled.\n     *  * The CloningVisitor must be run on the AST prior to modification.\n     *  * The original tokens must be provided, using the getTokens() method on the lexer.\n     *\n     * @param Node[] $stmts Modified AST with links to original AST\n     * @param Node[] $origStmts Original AST with token offset information\n     * @param Token[] $origTokens Tokens of the original code\n     */\n    public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string;\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/PrettyPrinterAbstract.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nuse PhpParser\\Internal\\DiffElem;\nuse PhpParser\\Internal\\Differ;\nuse PhpParser\\Internal\\PrintableNewAnonClassNode;\nuse PhpParser\\Internal\\TokenStream;\nuse PhpParser\\Node\\AttributeGroup;\nuse PhpParser\\Node\\Expr;\nuse PhpParser\\Node\\Expr\\AssignOp;\nuse PhpParser\\Node\\Expr\\BinaryOp;\nuse PhpParser\\Node\\Expr\\Cast;\nuse PhpParser\\Node\\IntersectionType;\nuse PhpParser\\Node\\MatchArm;\nuse PhpParser\\Node\\Param;\nuse PhpParser\\Node\\PropertyHook;\nuse PhpParser\\Node\\Scalar;\nuse PhpParser\\Node\\Stmt;\nuse PhpParser\\Node\\UnionType;\n\nabstract class PrettyPrinterAbstract implements PrettyPrinter {\n    protected const FIXUP_PREC_LEFT = 0; // LHS operand affected by precedence\n    protected const FIXUP_PREC_RIGHT = 1; // RHS operand affected by precedence\n    protected const FIXUP_PREC_UNARY = 2; // Only operand affected by precedence\n    protected const FIXUP_CALL_LHS = 3; // LHS of call\n    protected const FIXUP_DEREF_LHS = 4; // LHS of dereferencing operation\n    protected const FIXUP_STATIC_DEREF_LHS = 5; // LHS of static dereferencing operation\n    protected const FIXUP_BRACED_NAME  = 6; // Name operand that may require bracing\n    protected const FIXUP_VAR_BRACED_NAME = 7; // Name operand that may require ${} bracing\n    protected const FIXUP_ENCAPSED = 8; // Encapsed string part\n    protected const FIXUP_NEW = 9; // New/instanceof operand\n\n    protected const MAX_PRECEDENCE = 1000;\n\n    /** @var array<class-string, array{int, int, int}> */\n    protected array $precedenceMap = [\n        // [precedence, precedenceLHS, precedenceRHS]\n        // Where the latter two are the precedences to use for the LHS and RHS of a binary operator,\n        // where 1 is added to one of the sides depending on associativity. This information is not\n        // used for unary operators and set to -1.\n        Expr\\Clone_::class             => [-10,   0,   1],\n        BinaryOp\\Pow::class            => [  0,   0,   1],\n        Expr\\BitwiseNot::class         => [ 10,  -1,  -1],\n        Expr\\UnaryPlus::class          => [ 10,  -1,  -1],\n        Expr\\UnaryMinus::class         => [ 10,  -1,  -1],\n        Cast\\Int_::class               => [ 10,  -1,  -1],\n        Cast\\Double::class             => [ 10,  -1,  -1],\n        Cast\\String_::class            => [ 10,  -1,  -1],\n        Cast\\Array_::class             => [ 10,  -1,  -1],\n        Cast\\Object_::class            => [ 10,  -1,  -1],\n        Cast\\Bool_::class              => [ 10,  -1,  -1],\n        Cast\\Unset_::class             => [ 10,  -1,  -1],\n        Expr\\ErrorSuppress::class      => [ 10,  -1,  -1],\n        Expr\\Instanceof_::class        => [ 20,  -1,  -1],\n        Expr\\BooleanNot::class         => [ 30,  -1,  -1],\n        BinaryOp\\Mul::class            => [ 40,  41,  40],\n        BinaryOp\\Div::class            => [ 40,  41,  40],\n        BinaryOp\\Mod::class            => [ 40,  41,  40],\n        BinaryOp\\Plus::class           => [ 50,  51,  50],\n        BinaryOp\\Minus::class          => [ 50,  51,  50],\n        // FIXME: This precedence is incorrect for PHP 8.\n        BinaryOp\\Concat::class         => [ 50,  51,  50],\n        BinaryOp\\ShiftLeft::class      => [ 60,  61,  60],\n        BinaryOp\\ShiftRight::class     => [ 60,  61,  60],\n        BinaryOp\\Pipe::class           => [ 65,  66,  65],\n        BinaryOp\\Smaller::class        => [ 70,  70,  70],\n        BinaryOp\\SmallerOrEqual::class => [ 70,  70,  70],\n        BinaryOp\\Greater::class        => [ 70,  70,  70],\n        BinaryOp\\GreaterOrEqual::class => [ 70,  70,  70],\n        BinaryOp\\Equal::class          => [ 80,  80,  80],\n        BinaryOp\\NotEqual::class       => [ 80,  80,  80],\n        BinaryOp\\Identical::class      => [ 80,  80,  80],\n        BinaryOp\\NotIdentical::class   => [ 80,  80,  80],\n        BinaryOp\\Spaceship::class      => [ 80,  80,  80],\n        BinaryOp\\BitwiseAnd::class     => [ 90,  91,  90],\n        BinaryOp\\BitwiseXor::class     => [100, 101, 100],\n        BinaryOp\\BitwiseOr::class      => [110, 111, 110],\n        BinaryOp\\BooleanAnd::class     => [120, 121, 120],\n        BinaryOp\\BooleanOr::class      => [130, 131, 130],\n        BinaryOp\\Coalesce::class       => [140, 140, 141],\n        Expr\\Ternary::class            => [150, 150, 150],\n        Expr\\Assign::class             => [160,  -1,  -1],\n        Expr\\AssignRef::class          => [160,  -1,  -1],\n        AssignOp\\Plus::class           => [160,  -1,  -1],\n        AssignOp\\Minus::class          => [160,  -1,  -1],\n        AssignOp\\Mul::class            => [160,  -1,  -1],\n        AssignOp\\Div::class            => [160,  -1,  -1],\n        AssignOp\\Concat::class         => [160,  -1,  -1],\n        AssignOp\\Mod::class            => [160,  -1,  -1],\n        AssignOp\\BitwiseAnd::class     => [160,  -1,  -1],\n        AssignOp\\BitwiseOr::class      => [160,  -1,  -1],\n        AssignOp\\BitwiseXor::class     => [160,  -1,  -1],\n        AssignOp\\ShiftLeft::class      => [160,  -1,  -1],\n        AssignOp\\ShiftRight::class     => [160,  -1,  -1],\n        AssignOp\\Pow::class            => [160,  -1,  -1],\n        AssignOp\\Coalesce::class       => [160,  -1,  -1],\n        Expr\\YieldFrom::class          => [170,  -1,  -1],\n        Expr\\Yield_::class             => [175,  -1,  -1],\n        Expr\\Print_::class             => [180,  -1,  -1],\n        BinaryOp\\LogicalAnd::class     => [190, 191, 190],\n        BinaryOp\\LogicalXor::class     => [200, 201, 200],\n        BinaryOp\\LogicalOr::class      => [210, 211, 210],\n        Expr\\Include_::class           => [220,  -1,  -1],\n        Expr\\ArrowFunction::class      => [230,  -1,  -1],\n        Expr\\Throw_::class             => [240,  -1,  -1],\n        Expr\\Cast\\Void_::class         => [250,  -1,  -1],\n    ];\n\n    /** @var int Current indentation level. */\n    protected int $indentLevel;\n    /** @var string String for single level of indentation */\n    private string $indent;\n    /** @var int Width in spaces to indent by. */\n    private int $indentWidth;\n    /** @var bool Whether to use tab indentation. */\n    private bool $useTabs;\n    /** @var int Width in spaces of one tab. */\n    private int $tabWidth = 4;\n\n    /** @var string Newline style. Does not include current indentation. */\n    protected string $newline;\n    /** @var string Newline including current indentation. */\n    protected string $nl;\n    /** @var string|null Token placed at end of doc string to ensure it is followed by a newline.\n     *                   Null if flexible doc strings are used. */\n    protected ?string $docStringEndToken;\n    /** @var bool Whether semicolon namespaces can be used (i.e. no global namespace is used) */\n    protected bool $canUseSemicolonNamespaces;\n    /** @var bool Whether to use short array syntax if the node specifies no preference */\n    protected bool $shortArraySyntax;\n    /** @var PhpVersion PHP version to target */\n    protected PhpVersion $phpVersion;\n\n    /** @var TokenStream|null Original tokens for use in format-preserving pretty print */\n    protected ?TokenStream $origTokens;\n    /** @var Internal\\Differ<Node> Differ for node lists */\n    protected Differ $nodeListDiffer;\n    /** @var array<string, bool> Map determining whether a certain character is a label character */\n    protected array $labelCharMap;\n    /**\n     * @var array<string, array<string, int>> Map from token classes and subnode names to FIXUP_* constants.\n     *                                        This is used during format-preserving prints to place additional parens/braces if necessary.\n     */\n    protected array $fixupMap;\n    /**\n     * @var array<string, array{left?: int|string, right?: int|string}> Map from \"{$node->getType()}->{$subNode}\"\n     *                                                                  to ['left' => $l, 'right' => $r], where $l and $r specify the token type that needs to be stripped\n     *                                                                  when removing this node.\n     */\n    protected array $removalMap;\n    /**\n     * @var array<string, array{int|string|null, bool, string|null, string|null}> Map from\n     *                                                                            \"{$node->getType()}->{$subNode}\" to [$find, $beforeToken, $extraLeft, $extraRight].\n     *                                                                            $find is an optional token after which the insertion occurs. $extraLeft/Right\n     *                                                                            are optionally added before/after the main insertions.\n     */\n    protected array $insertionMap;\n    /**\n     * @var array<string, string> Map From \"{$class}->{$subNode}\" to string that should be inserted\n     *                            between elements of this list subnode.\n     */\n    protected array $listInsertionMap;\n\n    /**\n     * @var array<string, array{int|string|null, string, string}>\n     */\n    protected array $emptyListInsertionMap;\n    /** @var array<string, array{string, int, int}>\n     *       Map from \"{$class}->{$subNode}\" to [$printFn, $skipToken, $findToken] where $printFn is the function to\n     *       print the modifiers, $skipToken is the token to skip at the start and $findToken is the token before which\n     *       the modifiers should be reprinted. */\n    protected array $modifierChangeMap;\n\n    /**\n     * Creates a pretty printer instance using the given options.\n     *\n     * Supported options:\n     *  * PhpVersion $phpVersion: The PHP version to target (default to PHP 7.4). This option\n     *                            controls compatibility of the generated code with older PHP\n     *                            versions in cases where a simple stylistic choice exists (e.g.\n     *                            array() vs []). It is safe to pretty-print an AST for a newer\n     *                            PHP version while specifying an older target (but the result will\n     *                            of course not be compatible with the older version in that case).\n     *  * string $newline:        The newline style to use. Should be \"\\n\" (default) or \"\\r\\n\".\n     *  * string $indent:         The indentation to use. Should either be all spaces or a single\n     *                            tab. Defaults to four spaces (\"    \").\n     *  * bool $shortArraySyntax: Whether to use [] instead of array() as the default array\n     *                            syntax, if the node does not specify a format. Defaults to whether\n     *                            the phpVersion support short array syntax.\n     *\n     * @param array{\n     *     phpVersion?: PhpVersion, newline?: string, indent?: string, shortArraySyntax?: bool\n     * } $options Dictionary of formatting options\n     */\n    public function __construct(array $options = []) {\n        $this->phpVersion = $options['phpVersion'] ?? PhpVersion::fromComponents(7, 4);\n\n        $this->newline = $options['newline'] ?? \"\\n\";\n        if ($this->newline !== \"\\n\" && $this->newline != \"\\r\\n\") {\n            throw new \\LogicException('Option \"newline\" must be one of \"\\n\" or \"\\r\\n\"');\n        }\n\n        $this->shortArraySyntax =\n            $options['shortArraySyntax'] ?? $this->phpVersion->supportsShortArraySyntax();\n        $this->docStringEndToken =\n            $this->phpVersion->supportsFlexibleHeredoc() ? null : '_DOC_STRING_END_' . mt_rand();\n\n        $this->indent = $indent = $options['indent'] ?? '    ';\n        if ($indent === \"\\t\") {\n            $this->useTabs = true;\n            $this->indentWidth = $this->tabWidth;\n        } elseif ($indent === \\str_repeat(' ', \\strlen($indent))) {\n            $this->useTabs = false;\n            $this->indentWidth = \\strlen($indent);\n        } else {\n            throw new \\LogicException('Option \"indent\" must either be all spaces or a single tab');\n        }\n    }\n\n    /**\n     * Reset pretty printing state.\n     */\n    protected function resetState(): void {\n        $this->indentLevel = 0;\n        $this->nl = $this->newline;\n        $this->origTokens = null;\n    }\n\n    /**\n     * Set indentation level\n     *\n     * @param int $level Level in number of spaces\n     */\n    protected function setIndentLevel(int $level): void {\n        $this->indentLevel = $level;\n        if ($this->useTabs) {\n            $tabs = \\intdiv($level, $this->tabWidth);\n            $spaces = $level % $this->tabWidth;\n            $this->nl = $this->newline . \\str_repeat(\"\\t\", $tabs) . \\str_repeat(' ', $spaces);\n        } else {\n            $this->nl = $this->newline . \\str_repeat(' ', $level);\n        }\n    }\n\n    /**\n     * Increase indentation level.\n     */\n    protected function indent(): void {\n        $this->indentLevel += $this->indentWidth;\n        $this->nl .= $this->indent;\n    }\n\n    /**\n     * Decrease indentation level.\n     */\n    protected function outdent(): void {\n        assert($this->indentLevel >= $this->indentWidth);\n        $this->setIndentLevel($this->indentLevel - $this->indentWidth);\n    }\n\n    /**\n     * Pretty prints an array of statements.\n     *\n     * @param Node[] $stmts Array of statements\n     *\n     * @return string Pretty printed statements\n     */\n    public function prettyPrint(array $stmts): string {\n        $this->resetState();\n        $this->preprocessNodes($stmts);\n\n        return ltrim($this->handleMagicTokens($this->pStmts($stmts, false)));\n    }\n\n    /**\n     * Pretty prints an expression.\n     *\n     * @param Expr $node Expression node\n     *\n     * @return string Pretty printed node\n     */\n    public function prettyPrintExpr(Expr $node): string {\n        $this->resetState();\n        return $this->handleMagicTokens($this->p($node));\n    }\n\n    /**\n     * Pretty prints a file of statements (includes the opening <?php tag if it is required).\n     *\n     * @param Node[] $stmts Array of statements\n     *\n     * @return string Pretty printed statements\n     */\n    public function prettyPrintFile(array $stmts): string {\n        if (!$stmts) {\n            return \"<?php\" . $this->newline . $this->newline;\n        }\n\n        $p = \"<?php\" . $this->newline . $this->newline . $this->prettyPrint($stmts);\n\n        if ($stmts[0] instanceof Stmt\\InlineHTML) {\n            $p = preg_replace('/^<\\?php\\s+\\?>\\r?\\n?/', '', $p);\n        }\n        if ($stmts[count($stmts) - 1] instanceof Stmt\\InlineHTML) {\n            $p = preg_replace('/<\\?php$/', '', rtrim($p));\n        }\n\n        return $p;\n    }\n\n    /**\n     * Preprocesses the top-level nodes to initialize pretty printer state.\n     *\n     * @param Node[] $nodes Array of nodes\n     */\n    protected function preprocessNodes(array $nodes): void {\n        /* We can use semicolon-namespaces unless there is a global namespace declaration */\n        $this->canUseSemicolonNamespaces = true;\n        foreach ($nodes as $node) {\n            if ($node instanceof Stmt\\Namespace_ && null === $node->name) {\n                $this->canUseSemicolonNamespaces = false;\n                break;\n            }\n        }\n    }\n\n    /**\n     * Handles (and removes) doc-string-end tokens.\n     */\n    protected function handleMagicTokens(string $str): string {\n        if ($this->docStringEndToken !== null) {\n            // Replace doc-string-end tokens with nothing or a newline\n            $str = str_replace(\n                $this->docStringEndToken . ';' . $this->newline,\n                ';' . $this->newline,\n                $str);\n            $str = str_replace($this->docStringEndToken, $this->newline, $str);\n        }\n\n        return $str;\n    }\n\n    /**\n     * Pretty prints an array of nodes (statements) and indents them optionally.\n     *\n     * @param Node[] $nodes Array of nodes\n     * @param bool $indent Whether to indent the printed nodes\n     *\n     * @return string Pretty printed statements\n     */\n    protected function pStmts(array $nodes, bool $indent = true): string {\n        if ($indent) {\n            $this->indent();\n        }\n\n        $result = '';\n        foreach ($nodes as $node) {\n            $comments = $node->getComments();\n            if ($comments) {\n                $result .= $this->nl . $this->pComments($comments);\n                if ($node instanceof Stmt\\Nop) {\n                    continue;\n                }\n            }\n\n            $result .= $this->nl . $this->p($node);\n        }\n\n        if ($indent) {\n            $this->outdent();\n        }\n\n        return $result;\n    }\n\n    /**\n     * Pretty-print an infix operation while taking precedence into account.\n     *\n     * @param string $class Node class of operator\n     * @param Node $leftNode Left-hand side node\n     * @param string $operatorString String representation of the operator\n     * @param Node $rightNode Right-hand side node\n     * @param int $precedence Precedence of parent operator\n     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator\n     *\n     * @return string Pretty printed infix operation\n     */\n    protected function pInfixOp(\n        string $class, Node $leftNode, string $operatorString, Node $rightNode,\n        int $precedence, int $lhsPrecedence\n    ): string {\n        list($opPrecedence, $newPrecedenceLHS, $newPrecedenceRHS) = $this->precedenceMap[$class];\n        $prefix = '';\n        $suffix = '';\n        if ($opPrecedence >= $precedence) {\n            $prefix = '(';\n            $suffix = ')';\n            $lhsPrecedence = self::MAX_PRECEDENCE;\n        }\n        return $prefix . $this->p($leftNode, $newPrecedenceLHS, $newPrecedenceLHS)\n            . $operatorString . $this->p($rightNode, $newPrecedenceRHS, $lhsPrecedence) . $suffix;\n    }\n\n    /**\n     * Pretty-print a prefix operation while taking precedence into account.\n     *\n     * @param string $class Node class of operator\n     * @param string $operatorString String representation of the operator\n     * @param Node $node Node\n     * @param int $precedence Precedence of parent operator\n     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator\n     *\n     * @return string Pretty printed prefix operation\n     */\n    protected function pPrefixOp(string $class, string $operatorString, Node $node, int $precedence, int $lhsPrecedence): string {\n        $opPrecedence = $this->precedenceMap[$class][0];\n        $prefix = '';\n        $suffix = '';\n        if ($opPrecedence >= $lhsPrecedence) {\n            $prefix = '(';\n            $suffix = ')';\n            $lhsPrecedence = self::MAX_PRECEDENCE;\n        }\n        $printedArg = $this->p($node, $opPrecedence, $lhsPrecedence);\n        if (($operatorString === '+' && $printedArg[0] === '+') ||\n            ($operatorString === '-' && $printedArg[0] === '-')\n        ) {\n            // Avoid printing +(+$a) as ++$a and similar.\n            $printedArg = '(' . $printedArg . ')';\n        }\n        return $prefix . $operatorString . $printedArg . $suffix;\n    }\n\n    /**\n     * Pretty-print a postfix operation while taking precedence into account.\n     *\n     * @param string $class Node class of operator\n     * @param string $operatorString String representation of the operator\n     * @param Node $node Node\n     * @param int $precedence Precedence of parent operator\n     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator\n     *\n     * @return string Pretty printed postfix operation\n     */\n    protected function pPostfixOp(string $class, Node $node, string $operatorString, int $precedence, int $lhsPrecedence): string {\n        $opPrecedence = $this->precedenceMap[$class][0];\n        $prefix = '';\n        $suffix = '';\n        if ($opPrecedence >= $precedence) {\n            $prefix = '(';\n            $suffix = ')';\n            $lhsPrecedence = self::MAX_PRECEDENCE;\n        }\n        if ($opPrecedence < $lhsPrecedence) {\n            $lhsPrecedence = $opPrecedence;\n        }\n        return $prefix . $this->p($node, $opPrecedence, $lhsPrecedence) . $operatorString . $suffix;\n    }\n\n    /**\n     * Pretty prints an array of nodes and implodes the printed values.\n     *\n     * @param Node[] $nodes Array of Nodes to be printed\n     * @param string $glue Character to implode with\n     *\n     * @return string Imploded pretty printed nodes> $pre\n     */\n    protected function pImplode(array $nodes, string $glue = ''): string {\n        $pNodes = [];\n        foreach ($nodes as $node) {\n            if (null === $node) {\n                $pNodes[] = '';\n            } else {\n                $pNodes[] = $this->p($node);\n            }\n        }\n\n        return implode($glue, $pNodes);\n    }\n\n    /**\n     * Pretty prints an array of nodes and implodes the printed values with commas.\n     *\n     * @param Node[] $nodes Array of Nodes to be printed\n     *\n     * @return string Comma separated pretty printed nodes\n     */\n    protected function pCommaSeparated(array $nodes): string {\n        return $this->pImplode($nodes, ', ');\n    }\n\n    /**\n     * Pretty prints a comma-separated list of nodes in multiline style, including comments.\n     *\n     * The result includes a leading newline and one level of indentation (same as pStmts).\n     *\n     * @param Node[] $nodes Array of Nodes to be printed\n     * @param bool $trailingComma Whether to use a trailing comma\n     *\n     * @return string Comma separated pretty printed nodes in multiline style\n     */\n    protected function pCommaSeparatedMultiline(array $nodes, bool $trailingComma): string {\n        $this->indent();\n\n        $result = '';\n        $lastIdx = count($nodes) - 1;\n        foreach ($nodes as $idx => $node) {\n            if ($node !== null) {\n                $comments = $node->getComments();\n                if ($comments) {\n                    $result .= $this->nl . $this->pComments($comments);\n                }\n\n                $result .= $this->nl . $this->p($node);\n            } else {\n                $result .= $this->nl;\n            }\n            if ($trailingComma || $idx !== $lastIdx) {\n                $result .= ',';\n            }\n        }\n\n        $this->outdent();\n        return $result;\n    }\n\n    /**\n     * Prints reformatted text of the passed comments.\n     *\n     * @param Comment[] $comments List of comments\n     *\n     * @return string Reformatted text of comments\n     */\n    protected function pComments(array $comments): string {\n        $formattedComments = [];\n\n        foreach ($comments as $comment) {\n            $formattedComments[] = str_replace(\"\\n\", $this->nl, $comment->getReformattedText());\n        }\n\n        return implode($this->nl, $formattedComments);\n    }\n\n    /**\n     * Perform a format-preserving pretty print of an AST.\n     *\n     * The format preservation is best effort. For some changes to the AST the formatting will not\n     * be preserved (at least not locally).\n     *\n     * In order to use this method a number of prerequisites must be satisfied:\n     *  * The startTokenPos and endTokenPos attributes in the lexer must be enabled.\n     *  * The CloningVisitor must be run on the AST prior to modification.\n     *  * The original tokens must be provided, using the getTokens() method on the lexer.\n     *\n     * @param Node[] $stmts Modified AST with links to original AST\n     * @param Node[] $origStmts Original AST with token offset information\n     * @param Token[] $origTokens Tokens of the original code\n     */\n    public function printFormatPreserving(array $stmts, array $origStmts, array $origTokens): string {\n        $this->initializeNodeListDiffer();\n        $this->initializeLabelCharMap();\n        $this->initializeFixupMap();\n        $this->initializeRemovalMap();\n        $this->initializeInsertionMap();\n        $this->initializeListInsertionMap();\n        $this->initializeEmptyListInsertionMap();\n        $this->initializeModifierChangeMap();\n\n        $this->resetState();\n        $this->origTokens = new TokenStream($origTokens, $this->tabWidth);\n\n        $this->preprocessNodes($stmts);\n\n        $pos = 0;\n        $result = $this->pArray($stmts, $origStmts, $pos, 0, 'File', 'stmts', null);\n        if (null !== $result) {\n            $result .= $this->origTokens->getTokenCode($pos, count($origTokens) - 1, 0);\n        } else {\n            // Fallback\n            // TODO Add <?php properly\n            $result = \"<?php\" . $this->newline . $this->pStmts($stmts, false);\n        }\n\n        return $this->handleMagicTokens($result);\n    }\n\n    protected function pFallback(Node $node, int $precedence, int $lhsPrecedence): string {\n        return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);\n    }\n\n    /**\n     * Pretty prints a node.\n     *\n     * This method also handles formatting preservation for nodes.\n     *\n     * @param Node $node Node to be pretty printed\n     * @param int $precedence Precedence of parent operator\n     * @param int $lhsPrecedence Precedence for unary operator on LHS of binary operator\n     * @param bool $parentFormatPreserved Whether parent node has preserved formatting\n     *\n     * @return string Pretty printed node\n     */\n    protected function p(\n        Node $node, int $precedence = self::MAX_PRECEDENCE, int $lhsPrecedence = self::MAX_PRECEDENCE,\n        bool $parentFormatPreserved = false\n    ): string {\n        // No orig tokens means this is a normal pretty print without preservation of formatting\n        if (!$this->origTokens) {\n            return $this->{'p' . $node->getType()}($node, $precedence, $lhsPrecedence);\n        }\n\n        /** @var Node|null $origNode */\n        $origNode = $node->getAttribute('origNode');\n        if (null === $origNode) {\n            return $this->pFallback($node, $precedence, $lhsPrecedence);\n        }\n\n        $class = \\get_class($node);\n        \\assert($class === \\get_class($origNode));\n\n        $startPos = $origNode->getStartTokenPos();\n        $endPos = $origNode->getEndTokenPos();\n        \\assert($startPos >= 0 && $endPos >= 0);\n\n        $fallbackNode = $node;\n        if ($node instanceof Expr\\New_ && $node->class instanceof Stmt\\Class_) {\n            // Normalize node structure of anonymous classes\n            assert($origNode instanceof Expr\\New_);\n            $node = PrintableNewAnonClassNode::fromNewNode($node);\n            $origNode = PrintableNewAnonClassNode::fromNewNode($origNode);\n            $class = PrintableNewAnonClassNode::class;\n        }\n\n        // InlineHTML node does not contain closing and opening PHP tags. If the parent formatting\n        // is not preserved, then we need to use the fallback code to make sure the tags are\n        // printed.\n        if ($node instanceof Stmt\\InlineHTML && !$parentFormatPreserved) {\n            return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);\n        }\n\n        $indentAdjustment = $this->indentLevel - $this->origTokens->getIndentationBefore($startPos);\n\n        $type = $node->getType();\n        $fixupInfo = $this->fixupMap[$class] ?? null;\n\n        $result = '';\n        $pos = $startPos;\n        foreach ($node->getSubNodeNames() as $subNodeName) {\n            $subNode = $node->$subNodeName;\n            $origSubNode = $origNode->$subNodeName;\n\n            if ((!$subNode instanceof Node && $subNode !== null)\n                || (!$origSubNode instanceof Node && $origSubNode !== null)\n            ) {\n                if ($subNode === $origSubNode) {\n                    // Unchanged, can reuse old code\n                    continue;\n                }\n\n                if (is_array($subNode) && is_array($origSubNode)) {\n                    // Array subnode changed, we might be able to reconstruct it\n                    $listResult = $this->pArray(\n                        $subNode, $origSubNode, $pos, $indentAdjustment, $class, $subNodeName,\n                        $fixupInfo[$subNodeName] ?? null\n                    );\n                    if (null === $listResult) {\n                        return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);\n                    }\n\n                    $result .= $listResult;\n                    continue;\n                }\n\n                // Check if this is a modifier change\n                $key = $class . '->' . $subNodeName;\n                if (!isset($this->modifierChangeMap[$key])) {\n                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);\n                }\n\n                [$printFn, $skipToken, $findToken] = $this->modifierChangeMap[$key];\n                $skipWSPos = $this->origTokens->skipRight($pos, $skipToken);\n                $result .= $this->origTokens->getTokenCode($pos, $skipWSPos, $indentAdjustment);\n                $result .= $this->$printFn($subNode);\n                $pos = $this->origTokens->findRight($skipWSPos, $findToken);\n                continue;\n            }\n\n            $extraLeft = '';\n            $extraRight = '';\n            if ($origSubNode !== null) {\n                $subStartPos = $origSubNode->getStartTokenPos();\n                $subEndPos = $origSubNode->getEndTokenPos();\n                \\assert($subStartPos >= 0 && $subEndPos >= 0);\n            } else {\n                if ($subNode === null) {\n                    // Both null, nothing to do\n                    continue;\n                }\n\n                // A node has been inserted, check if we have insertion information for it\n                $key = $type . '->' . $subNodeName;\n                if (!isset($this->insertionMap[$key])) {\n                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);\n                }\n\n                list($findToken, $beforeToken, $extraLeft, $extraRight) = $this->insertionMap[$key];\n                if (null !== $findToken) {\n                    $subStartPos = $this->origTokens->findRight($pos, $findToken)\n                        + (int) !$beforeToken;\n                } else {\n                    $subStartPos = $pos;\n                }\n\n                if (null === $extraLeft && null !== $extraRight) {\n                    // If inserting on the right only, skipping whitespace looks better\n                    $subStartPos = $this->origTokens->skipRightWhitespace($subStartPos);\n                }\n                $subEndPos = $subStartPos - 1;\n            }\n\n            if (null === $subNode) {\n                // A node has been removed, check if we have removal information for it\n                $key = $type . '->' . $subNodeName;\n                if (!isset($this->removalMap[$key])) {\n                    return $this->pFallback($fallbackNode, $precedence, $lhsPrecedence);\n                }\n\n                // Adjust positions to account for additional tokens that must be skipped\n                $removalInfo = $this->removalMap[$key];\n                if (isset($removalInfo['left'])) {\n                    $subStartPos = $this->origTokens->skipLeft($subStartPos - 1, $removalInfo['left']) + 1;\n                }\n                if (isset($removalInfo['right'])) {\n                    $subEndPos = $this->origTokens->skipRight($subEndPos + 1, $removalInfo['right']) - 1;\n                }\n            }\n\n            $result .= $this->origTokens->getTokenCode($pos, $subStartPos, $indentAdjustment);\n\n            if (null !== $subNode) {\n                $result .= $extraLeft;\n\n                $origIndentLevel = $this->indentLevel;\n                $this->setIndentLevel(max($this->origTokens->getIndentationBefore($subStartPos) + $indentAdjustment, 0));\n\n                // If it's the same node that was previously in this position, it certainly doesn't\n                // need fixup. It's important to check this here, because our fixup checks are more\n                // conservative than strictly necessary.\n                if (isset($fixupInfo[$subNodeName])\n                    && $subNode->getAttribute('origNode') !== $origSubNode\n                ) {\n                    $fixup = $fixupInfo[$subNodeName];\n                    $res = $this->pFixup($fixup, $subNode, $class, $subStartPos, $subEndPos);\n                } else {\n                    $res = $this->p($subNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);\n                }\n\n                $this->safeAppend($result, $res);\n                $this->setIndentLevel($origIndentLevel);\n\n                $result .= $extraRight;\n            }\n\n            $pos = $subEndPos + 1;\n        }\n\n        $result .= $this->origTokens->getTokenCode($pos, $endPos + 1, $indentAdjustment);\n        return $result;\n    }\n\n    /**\n     * Perform a format-preserving pretty print of an array.\n     *\n     * @param Node[] $nodes New nodes\n     * @param Node[] $origNodes Original nodes\n     * @param int $pos Current token position (updated by reference)\n     * @param int $indentAdjustment Adjustment for indentation\n     * @param string $parentNodeClass Class of the containing node.\n     * @param string $subNodeName Name of array subnode.\n     * @param null|int $fixup Fixup information for array item nodes\n     *\n     * @return null|string Result of pretty print or null if cannot preserve formatting\n     */\n    protected function pArray(\n        array  $nodes, array $origNodes, int &$pos, int $indentAdjustment,\n        string $parentNodeClass, string $subNodeName, ?int $fixup\n    ): ?string {\n        $diff = $this->nodeListDiffer->diffWithReplacements($origNodes, $nodes);\n\n        $mapKey = $parentNodeClass . '->' . $subNodeName;\n        $insertStr = $this->listInsertionMap[$mapKey] ?? null;\n        $isStmtList = $subNodeName === 'stmts';\n\n        $beforeFirstKeepOrReplace = true;\n        $skipRemovedNode = false;\n        $delayedAdd = [];\n        $lastElemIndentLevel = $this->indentLevel;\n\n        $insertNewline = false;\n        if ($insertStr === \"\\n\") {\n            $insertStr = '';\n            $insertNewline = true;\n        }\n\n        if ($isStmtList && \\count($origNodes) === 1 && \\count($nodes) !== 1) {\n            $startPos = $origNodes[0]->getStartTokenPos();\n            $endPos = $origNodes[0]->getEndTokenPos();\n            \\assert($startPos >= 0 && $endPos >= 0);\n            if (!$this->origTokens->haveBraces($startPos, $endPos)) {\n                // This was a single statement without braces, but either additional statements\n                // have been added, or the single statement has been removed. This requires the\n                // addition of braces. For now fall back.\n                // TODO: Try to preserve formatting\n                return null;\n            }\n        }\n\n        $result = '';\n        foreach ($diff as $i => $diffElem) {\n            $diffType = $diffElem->type;\n            /** @var Node|string|null $arrItem */\n            $arrItem = $diffElem->new;\n            /** @var Node|string|null $origArrItem */\n            $origArrItem = $diffElem->old;\n\n            if ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {\n                $beforeFirstKeepOrReplace = false;\n\n                if ($origArrItem === null || $arrItem === null) {\n                    // We can only handle the case where both are null\n                    if ($origArrItem === $arrItem) {\n                        continue;\n                    }\n                    return null;\n                }\n\n                if (!$arrItem instanceof Node || !$origArrItem instanceof Node) {\n                    // We can only deal with nodes. This can occur for Names, which use string arrays.\n                    return null;\n                }\n\n                $itemStartPos = $origArrItem->getStartTokenPos();\n                $itemEndPos = $origArrItem->getEndTokenPos();\n                \\assert($itemStartPos >= 0 && $itemEndPos >= 0 && $itemStartPos >= $pos);\n\n                $origIndentLevel = $this->indentLevel;\n                $lastElemIndentLevel = max($this->origTokens->getIndentationBefore($itemStartPos) + $indentAdjustment, 0);\n                $this->setIndentLevel($lastElemIndentLevel);\n\n                $comments = $arrItem->getComments();\n                $origComments = $origArrItem->getComments();\n                $commentStartPos = $origComments ? $origComments[0]->getStartTokenPos() : $itemStartPos;\n                \\assert($commentStartPos >= 0);\n\n                if ($commentStartPos < $pos) {\n                    // Comments may be assigned to multiple nodes if they start at the same position.\n                    // Make sure we don't try to print them multiple times.\n                    $commentStartPos = $itemStartPos;\n                }\n\n                if ($skipRemovedNode) {\n                    if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {\n                        // We'd remove an opening/closing PHP tag.\n                        // TODO: Preserve formatting.\n                        $this->setIndentLevel($origIndentLevel);\n                        return null;\n                    }\n                } else {\n                    $result .= $this->origTokens->getTokenCode(\n                        $pos, $commentStartPos, $indentAdjustment);\n                }\n\n                if (!empty($delayedAdd)) {\n                    /** @var Node $delayedAddNode */\n                    foreach ($delayedAdd as $delayedAddNode) {\n                        if ($insertNewline) {\n                            $delayedAddComments = $delayedAddNode->getComments();\n                            if ($delayedAddComments) {\n                                $result .= $this->pComments($delayedAddComments) . $this->nl;\n                            }\n                        }\n\n                        $this->safeAppend($result, $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true));\n\n                        if ($insertNewline) {\n                            $result .= $insertStr . $this->nl;\n                        } else {\n                            $result .= $insertStr;\n                        }\n                    }\n\n                    $delayedAdd = [];\n                }\n\n                if ($comments !== $origComments) {\n                    if ($comments) {\n                        $result .= $this->pComments($comments) . $this->nl;\n                    }\n                } else {\n                    $result .= $this->origTokens->getTokenCode(\n                        $commentStartPos, $itemStartPos, $indentAdjustment);\n                }\n\n                // If we had to remove anything, we have done so now.\n                $skipRemovedNode = false;\n            } elseif ($diffType === DiffElem::TYPE_ADD) {\n                if (null === $insertStr) {\n                    // We don't have insertion information for this list type\n                    return null;\n                }\n\n                if (!$arrItem instanceof Node) {\n                    // We only support list insertion of nodes.\n                    return null;\n                }\n\n                // We go multiline if the original code was multiline,\n                // or if it's an array item with a comment above it.\n                // Match always uses multiline formatting.\n                if ($insertStr === ', ' &&\n                    ($this->isMultiline($origNodes) || $arrItem->getComments() ||\n                     $parentNodeClass === Expr\\Match_::class)\n                ) {\n                    $insertStr = ',';\n                    $insertNewline = true;\n                }\n\n                if ($beforeFirstKeepOrReplace) {\n                    // Will be inserted at the next \"replace\" or \"keep\" element\n                    $delayedAdd[] = $arrItem;\n                    continue;\n                }\n\n                $itemStartPos = $pos;\n                $itemEndPos = $pos - 1;\n\n                $origIndentLevel = $this->indentLevel;\n                $this->setIndentLevel($lastElemIndentLevel);\n\n                if ($insertNewline) {\n                    $result .= $insertStr . $this->nl;\n                    $comments = $arrItem->getComments();\n                    if ($comments) {\n                        $result .= $this->pComments($comments) . $this->nl;\n                    }\n                } else {\n                    $result .= $insertStr;\n                }\n            } elseif ($diffType === DiffElem::TYPE_REMOVE) {\n                if (!$origArrItem instanceof Node) {\n                    // We only support removal for nodes\n                    return null;\n                }\n\n                $itemStartPos = $origArrItem->getStartTokenPos();\n                $itemEndPos = $origArrItem->getEndTokenPos();\n                \\assert($itemStartPos >= 0 && $itemEndPos >= 0);\n\n                // Consider comments part of the node.\n                $origComments = $origArrItem->getComments();\n                if ($origComments) {\n                    $itemStartPos = $origComments[0]->getStartTokenPos();\n                }\n\n                if ($i === 0) {\n                    // If we're removing from the start, keep the tokens before the node and drop those after it,\n                    // instead of the other way around.\n                    $result .= $this->origTokens->getTokenCode(\n                        $pos, $itemStartPos, $indentAdjustment);\n                    $skipRemovedNode = true;\n                } else {\n                    if ($isStmtList && $this->origTokens->haveTagInRange($pos, $itemStartPos)) {\n                        // We'd remove an opening/closing PHP tag.\n                        // TODO: Preserve formatting.\n                        return null;\n                    }\n                }\n\n                $pos = $itemEndPos + 1;\n                continue;\n            } else {\n                throw new \\Exception(\"Shouldn't happen\");\n            }\n\n            if (null !== $fixup && $arrItem->getAttribute('origNode') !== $origArrItem) {\n                $res = $this->pFixup($fixup, $arrItem, null, $itemStartPos, $itemEndPos);\n            } else {\n                $res = $this->p($arrItem, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);\n            }\n            $this->safeAppend($result, $res);\n\n            $this->setIndentLevel($origIndentLevel);\n            $pos = $itemEndPos + 1;\n        }\n\n        if ($skipRemovedNode) {\n            // TODO: Support removing single node.\n            return null;\n        }\n\n        if (!empty($delayedAdd)) {\n            if (!isset($this->emptyListInsertionMap[$mapKey])) {\n                return null;\n            }\n\n            list($findToken, $extraLeft, $extraRight) = $this->emptyListInsertionMap[$mapKey];\n            if (null !== $findToken) {\n                // For anon classes skip to the class keyword.\n                $isAnonClassArgs = $mapKey === PrintableNewAnonClassNode::class . '->args';\n                if ($isAnonClassArgs) {\n                    $insertPos = $this->origTokens->findRight($pos, \\T_CLASS) + 1;\n                    $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment);\n                    $pos = $insertPos;\n                }\n\n                // If \"new Foo\" was used without arguments, we need to convert to \"new Foo()\".\n                if (($mapKey === Expr\\New_::class . '->args' || $isAnonClassArgs) &&\n                    !$this->origTokens->haveTokenImmediatelyAfter($pos - 1, '(')\n                ) {\n                    $extraLeft = '(';\n                    $extraRight = ')';\n                } else {\n                    $insertPos = $this->origTokens->findRight($pos, $findToken) + 1;\n                    $result .= $this->origTokens->getTokenCode($pos, $insertPos, $indentAdjustment);\n                    $pos = $insertPos;\n                }\n            }\n\n            $first = true;\n            $result .= $extraLeft;\n            foreach ($delayedAdd as $delayedAddNode) {\n                if (!$first) {\n                    $result .= $insertStr;\n                    if ($insertNewline) {\n                        $result .= $this->nl;\n                    }\n                }\n                $result .= $this->p($delayedAddNode, self::MAX_PRECEDENCE, self::MAX_PRECEDENCE, true);\n                $first = false;\n            }\n            $result .= $extraRight === \"\\n\" ? $this->nl : $extraRight;\n        }\n\n        return $result;\n    }\n\n    /**\n     * Print node with fixups.\n     *\n     * Fixups here refer to the addition of extra parentheses, braces or other characters, that\n     * are required to preserve program semantics in a certain context (e.g. to maintain precedence\n     * or because only certain expressions are allowed in certain places).\n     *\n     * @param int $fixup Fixup type\n     * @param Node $subNode Subnode to print\n     * @param string|null $parentClass Class of parent node\n     * @param int $subStartPos Original start pos of subnode\n     * @param int $subEndPos Original end pos of subnode\n     *\n     * @return string Result of fixed-up print of subnode\n     */\n    protected function pFixup(int $fixup, Node $subNode, ?string $parentClass, int $subStartPos, int $subEndPos): string {\n        switch ($fixup) {\n            case self::FIXUP_PREC_LEFT:\n                // We use a conservative approximation where lhsPrecedence == precedence.\n                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {\n                    $precedence = $this->precedenceMap[$parentClass][1];\n                    return $this->p($subNode, $precedence, $precedence);\n                }\n                break;\n            case self::FIXUP_PREC_RIGHT:\n                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {\n                    $precedence = $this->precedenceMap[$parentClass][2];\n                    return $this->p($subNode, $precedence, $precedence);\n                }\n                break;\n            case self::FIXUP_PREC_UNARY:\n                if (!$this->origTokens->haveParens($subStartPos, $subEndPos)) {\n                    $precedence = $this->precedenceMap[$parentClass][0];\n                    return $this->p($subNode, $precedence, $precedence);\n                }\n                break;\n            case self::FIXUP_CALL_LHS:\n                if ($this->callLhsRequiresParens($subNode)\n                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)\n                ) {\n                    return '(' . $this->p($subNode) . ')';\n                }\n                break;\n            case self::FIXUP_DEREF_LHS:\n                if ($this->dereferenceLhsRequiresParens($subNode)\n                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)\n                ) {\n                    return '(' . $this->p($subNode) . ')';\n                }\n                break;\n            case self::FIXUP_STATIC_DEREF_LHS:\n                if ($this->staticDereferenceLhsRequiresParens($subNode)\n                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)\n                ) {\n                    return '(' . $this->p($subNode) . ')';\n                }\n                break;\n            case self::FIXUP_NEW:\n                if ($this->newOperandRequiresParens($subNode)\n                    && !$this->origTokens->haveParens($subStartPos, $subEndPos)) {\n                    return '(' . $this->p($subNode) . ')';\n                }\n                break;\n            case self::FIXUP_BRACED_NAME:\n            case self::FIXUP_VAR_BRACED_NAME:\n                if ($subNode instanceof Expr\n                    && !$this->origTokens->haveBraces($subStartPos, $subEndPos)\n                ) {\n                    return ($fixup === self::FIXUP_VAR_BRACED_NAME ? '$' : '')\n                        . '{' . $this->p($subNode) . '}';\n                }\n                break;\n            case self::FIXUP_ENCAPSED:\n                if (!$subNode instanceof Node\\InterpolatedStringPart\n                    && !$this->origTokens->haveBraces($subStartPos, $subEndPos)\n                ) {\n                    return '{' . $this->p($subNode) . '}';\n                }\n                break;\n            default:\n                throw new \\Exception('Cannot happen');\n        }\n\n        // Nothing special to do\n        return $this->p($subNode);\n    }\n\n    /**\n     * Appends to a string, ensuring whitespace between label characters.\n     *\n     * Example: \"echo\" and \"$x\" result in \"echo$x\", but \"echo\" and \"x\" result in \"echo x\".\n     * Without safeAppend the result would be \"echox\", which does not preserve semantics.\n     */\n    protected function safeAppend(string &$str, string $append): void {\n        if ($str === \"\") {\n            $str = $append;\n            return;\n        }\n\n        if ($append === \"\") {\n            return;\n        }\n\n        if (!$this->labelCharMap[$append[0]]\n                || !$this->labelCharMap[$str[\\strlen($str) - 1]]) {\n            $str .= $append;\n        } else {\n            $str .= \" \" . $append;\n        }\n    }\n\n    /**\n     * Determines whether the LHS of a call must be wrapped in parenthesis.\n     *\n     * @param Node $node LHS of a call\n     *\n     * @return bool Whether parentheses are required\n     */\n    protected function callLhsRequiresParens(Node $node): bool {\n        if ($node instanceof Expr\\New_) {\n            return !$this->phpVersion->supportsNewDereferenceWithoutParentheses();\n        }\n        return !($node instanceof Node\\Name\n            || $node instanceof Expr\\Variable\n            || $node instanceof Expr\\ArrayDimFetch\n            || $node instanceof Expr\\FuncCall\n            || $node instanceof Expr\\MethodCall\n            || $node instanceof Expr\\NullsafeMethodCall\n            || $node instanceof Expr\\StaticCall\n            || $node instanceof Expr\\Array_);\n    }\n\n    /**\n     * Determines whether the LHS of an array/object operation must be wrapped in parentheses.\n     *\n     * @param Node $node LHS of dereferencing operation\n     *\n     * @return bool Whether parentheses are required\n     */\n    protected function dereferenceLhsRequiresParens(Node $node): bool {\n        // A constant can occur on the LHS of an array/object deref, but not a static deref.\n        return $this->staticDereferenceLhsRequiresParens($node)\n            && !$node instanceof Expr\\ConstFetch;\n    }\n\n    /**\n     * Determines whether the LHS of a static operation must be wrapped in parentheses.\n     *\n     * @param Node $node LHS of dereferencing operation\n     *\n     * @return bool Whether parentheses are required\n     */\n    protected function staticDereferenceLhsRequiresParens(Node $node): bool {\n        if ($node instanceof Expr\\New_) {\n            return !$this->phpVersion->supportsNewDereferenceWithoutParentheses();\n        }\n        return !($node instanceof Expr\\Variable\n            || $node instanceof Node\\Name\n            || $node instanceof Expr\\ArrayDimFetch\n            || $node instanceof Expr\\PropertyFetch\n            || $node instanceof Expr\\NullsafePropertyFetch\n            || $node instanceof Expr\\StaticPropertyFetch\n            || $node instanceof Expr\\FuncCall\n            || $node instanceof Expr\\MethodCall\n            || $node instanceof Expr\\NullsafeMethodCall\n            || $node instanceof Expr\\StaticCall\n            || $node instanceof Expr\\Array_\n            || $node instanceof Scalar\\String_\n            || $node instanceof Expr\\ClassConstFetch);\n    }\n\n    /**\n     * Determines whether an expression used in \"new\" or \"instanceof\" requires parentheses.\n     *\n     * @param Node $node New or instanceof operand\n     *\n     * @return bool Whether parentheses are required\n     */\n    protected function newOperandRequiresParens(Node $node): bool {\n        while (true) {\n            if ($node instanceof Node\\Name || $node instanceof Expr\\Variable) {\n                return false;\n            }\n            if ($node instanceof Expr\\ArrayDimFetch || $node instanceof Expr\\PropertyFetch ||\n                $node instanceof Expr\\NullsafePropertyFetch\n            ) {\n                $node = $node->var;\n                continue;\n            }\n            if ($node instanceof Expr\\StaticPropertyFetch) {\n                $node = $node->class;\n                continue;\n            }\n            return true;\n        }\n    }\n\n    /**\n     * Print modifiers, including trailing whitespace.\n     *\n     * @param int $modifiers Modifier mask to print\n     *\n     * @return string Printed modifiers\n     */\n    protected function pModifiers(int $modifiers): string {\n        return ($modifiers & Modifiers::FINAL ? 'final ' : '')\n             . ($modifiers & Modifiers::ABSTRACT ? 'abstract ' : '')\n             . ($modifiers & Modifiers::PUBLIC ? 'public ' : '')\n             . ($modifiers & Modifiers::PROTECTED ? 'protected ' : '')\n             . ($modifiers & Modifiers::PRIVATE ? 'private ' : '')\n             . ($modifiers & Modifiers::PUBLIC_SET ? 'public(set) ' : '')\n             . ($modifiers & Modifiers::PROTECTED_SET ? 'protected(set) ' : '')\n             . ($modifiers & Modifiers::PRIVATE_SET ? 'private(set) ' : '')\n             . ($modifiers & Modifiers::STATIC ? 'static ' : '')\n             . ($modifiers & Modifiers::READONLY ? 'readonly ' : '');\n    }\n\n    protected function pStatic(bool $static): string {\n        return $static ? 'static ' : '';\n    }\n\n    /**\n     * Determine whether a list of nodes uses multiline formatting.\n     *\n     * @param (Node|null)[] $nodes Node list\n     *\n     * @return bool Whether multiline formatting is used\n     */\n    protected function isMultiline(array $nodes): bool {\n        if (\\count($nodes) < 2) {\n            return false;\n        }\n\n        $pos = -1;\n        foreach ($nodes as $node) {\n            if (null === $node) {\n                continue;\n            }\n\n            $endPos = $node->getEndTokenPos() + 1;\n            if ($pos >= 0) {\n                $text = $this->origTokens->getTokenCode($pos, $endPos, 0);\n                if (false === strpos($text, \"\\n\")) {\n                    // We require that a newline is present between *every* item. If the formatting\n                    // is inconsistent, with only some items having newlines, we don't consider it\n                    // as multiline\n                    return false;\n                }\n            }\n            $pos = $endPos;\n        }\n\n        return true;\n    }\n\n    /**\n     * Lazily initializes label char map.\n     *\n     * The label char map determines whether a certain character may occur in a label.\n     */\n    protected function initializeLabelCharMap(): void {\n        if (isset($this->labelCharMap)) {\n            return;\n        }\n\n        $this->labelCharMap = [];\n        for ($i = 0; $i < 256; $i++) {\n            $chr = chr($i);\n            $this->labelCharMap[$chr] = (bool) preg_match('/^[a-zA-Z0-9_\\x80-\\xff]$/', $chr);\n        }\n\n        if ($this->phpVersion->allowsDelInIdentifiers()) {\n            $this->labelCharMap[\"\\x7f\"] = true;\n        }\n    }\n\n    /**\n     * Lazily initializes node list differ.\n     *\n     * The node list differ is used to determine differences between two array subnodes.\n     */\n    protected function initializeNodeListDiffer(): void {\n        if (isset($this->nodeListDiffer)) {\n            return;\n        }\n\n        $this->nodeListDiffer = new Internal\\Differ(function ($a, $b) {\n            if ($a instanceof Node && $b instanceof Node) {\n                return $a === $b->getAttribute('origNode');\n            }\n            // Can happen for array destructuring\n            return $a === null && $b === null;\n        });\n    }\n\n    /**\n     * Lazily initializes fixup map.\n     *\n     * The fixup map is used to determine whether a certain subnode of a certain node may require\n     * some kind of \"fixup\" operation, e.g. the addition of parenthesis or braces.\n     */\n    protected function initializeFixupMap(): void {\n        if (isset($this->fixupMap)) {\n            return;\n        }\n\n        $this->fixupMap = [\n            Expr\\Instanceof_::class => [\n                'expr' => self::FIXUP_PREC_UNARY,\n                'class' => self::FIXUP_NEW,\n            ],\n            Expr\\Ternary::class => [\n                'cond' => self::FIXUP_PREC_LEFT,\n                'else' => self::FIXUP_PREC_RIGHT,\n            ],\n            Expr\\Yield_::class => ['value' => self::FIXUP_PREC_UNARY],\n\n            Expr\\FuncCall::class => ['name' => self::FIXUP_CALL_LHS],\n            Expr\\StaticCall::class => ['class' => self::FIXUP_STATIC_DEREF_LHS],\n            Expr\\ArrayDimFetch::class => ['var' => self::FIXUP_DEREF_LHS],\n            Expr\\ClassConstFetch::class => [\n                'class' => self::FIXUP_STATIC_DEREF_LHS,\n                'name' => self::FIXUP_BRACED_NAME,\n            ],\n            Expr\\New_::class => ['class' => self::FIXUP_NEW],\n            Expr\\MethodCall::class => [\n                'var' => self::FIXUP_DEREF_LHS,\n                'name' => self::FIXUP_BRACED_NAME,\n            ],\n            Expr\\NullsafeMethodCall::class => [\n                'var' => self::FIXUP_DEREF_LHS,\n                'name' => self::FIXUP_BRACED_NAME,\n            ],\n            Expr\\StaticPropertyFetch::class => [\n                'class' => self::FIXUP_STATIC_DEREF_LHS,\n                'name' => self::FIXUP_VAR_BRACED_NAME,\n            ],\n            Expr\\PropertyFetch::class => [\n                'var' => self::FIXUP_DEREF_LHS,\n                'name' => self::FIXUP_BRACED_NAME,\n            ],\n            Expr\\NullsafePropertyFetch::class => [\n                'var' => self::FIXUP_DEREF_LHS,\n                'name' => self::FIXUP_BRACED_NAME,\n            ],\n            Scalar\\InterpolatedString::class => [\n                'parts' => self::FIXUP_ENCAPSED,\n            ],\n        ];\n\n        $binaryOps = [\n            BinaryOp\\Pow::class, BinaryOp\\Mul::class, BinaryOp\\Div::class, BinaryOp\\Mod::class,\n            BinaryOp\\Plus::class, BinaryOp\\Minus::class, BinaryOp\\Concat::class,\n            BinaryOp\\ShiftLeft::class, BinaryOp\\ShiftRight::class, BinaryOp\\Smaller::class,\n            BinaryOp\\SmallerOrEqual::class, BinaryOp\\Greater::class, BinaryOp\\GreaterOrEqual::class,\n            BinaryOp\\Equal::class, BinaryOp\\NotEqual::class, BinaryOp\\Identical::class,\n            BinaryOp\\NotIdentical::class, BinaryOp\\Spaceship::class, BinaryOp\\BitwiseAnd::class,\n            BinaryOp\\BitwiseXor::class, BinaryOp\\BitwiseOr::class, BinaryOp\\BooleanAnd::class,\n            BinaryOp\\BooleanOr::class, BinaryOp\\Coalesce::class, BinaryOp\\LogicalAnd::class,\n            BinaryOp\\LogicalXor::class, BinaryOp\\LogicalOr::class, BinaryOp\\Pipe::class,\n        ];\n        foreach ($binaryOps as $binaryOp) {\n            $this->fixupMap[$binaryOp] = [\n                'left' => self::FIXUP_PREC_LEFT,\n                'right' => self::FIXUP_PREC_RIGHT\n            ];\n        }\n\n        $prefixOps = [\n            Expr\\Clone_::class, Expr\\BitwiseNot::class, Expr\\BooleanNot::class, Expr\\UnaryPlus::class, Expr\\UnaryMinus::class,\n            Cast\\Int_::class, Cast\\Double::class, Cast\\String_::class, Cast\\Array_::class,\n            Cast\\Object_::class, Cast\\Bool_::class, Cast\\Unset_::class, Expr\\ErrorSuppress::class,\n            Expr\\YieldFrom::class, Expr\\Print_::class, Expr\\Include_::class,\n            Expr\\Assign::class, Expr\\AssignRef::class, AssignOp\\Plus::class, AssignOp\\Minus::class,\n            AssignOp\\Mul::class, AssignOp\\Div::class, AssignOp\\Concat::class, AssignOp\\Mod::class,\n            AssignOp\\BitwiseAnd::class, AssignOp\\BitwiseOr::class, AssignOp\\BitwiseXor::class,\n            AssignOp\\ShiftLeft::class, AssignOp\\ShiftRight::class, AssignOp\\Pow::class, AssignOp\\Coalesce::class,\n            Expr\\ArrowFunction::class, Expr\\Throw_::class,\n        ];\n        foreach ($prefixOps as $prefixOp) {\n            $this->fixupMap[$prefixOp] = ['expr' => self::FIXUP_PREC_UNARY];\n        }\n    }\n\n    /**\n     * Lazily initializes the removal map.\n     *\n     * The removal map is used to determine which additional tokens should be removed when a\n     * certain node is replaced by null.\n     */\n    protected function initializeRemovalMap(): void {\n        if (isset($this->removalMap)) {\n            return;\n        }\n\n        $stripBoth = ['left' => \\T_WHITESPACE, 'right' => \\T_WHITESPACE];\n        $stripLeft = ['left' => \\T_WHITESPACE];\n        $stripRight = ['right' => \\T_WHITESPACE];\n        $stripDoubleArrow = ['right' => \\T_DOUBLE_ARROW];\n        $stripColon = ['left' => ':'];\n        $stripEquals = ['left' => '='];\n        $this->removalMap = [\n            'Expr_ArrayDimFetch->dim' => $stripBoth,\n            'ArrayItem->key' => $stripDoubleArrow,\n            'Expr_ArrowFunction->returnType' => $stripColon,\n            'Expr_Closure->returnType' => $stripColon,\n            'Expr_Exit->expr' => $stripBoth,\n            'Expr_Ternary->if' => $stripBoth,\n            'Expr_Yield->key' => $stripDoubleArrow,\n            'Expr_Yield->value' => $stripBoth,\n            'Param->type' => $stripRight,\n            'Param->default' => $stripEquals,\n            'Stmt_Break->num' => $stripBoth,\n            'Stmt_Catch->var' => $stripLeft,\n            'Stmt_ClassConst->type' => $stripRight,\n            'Stmt_ClassMethod->returnType' => $stripColon,\n            'Stmt_Class->extends' => ['left' => \\T_EXTENDS],\n            'Stmt_Enum->scalarType' => $stripColon,\n            'Stmt_EnumCase->expr' => $stripEquals,\n            'Expr_PrintableNewAnonClass->extends' => ['left' => \\T_EXTENDS],\n            'Stmt_Continue->num' => $stripBoth,\n            'Stmt_Foreach->keyVar' => $stripDoubleArrow,\n            'Stmt_Function->returnType' => $stripColon,\n            'Stmt_If->else' => $stripLeft,\n            'Stmt_Namespace->name' => $stripLeft,\n            'Stmt_Property->type' => $stripRight,\n            'PropertyItem->default' => $stripEquals,\n            'Stmt_Return->expr' => $stripBoth,\n            'Stmt_StaticVar->default' => $stripEquals,\n            'Stmt_TraitUseAdaptation_Alias->newName' => $stripLeft,\n            'Stmt_TryCatch->finally' => $stripLeft,\n            // 'Stmt_Case->cond': Replace with \"default\"\n            // 'Stmt_Class->name': Unclear what to do\n            // 'Stmt_Declare->stmts': Not a plain node\n            // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a plain node\n        ];\n    }\n\n    protected function initializeInsertionMap(): void {\n        if (isset($this->insertionMap)) {\n            return;\n        }\n\n        // TODO: \"yield\" where both key and value are inserted doesn't work\n        // [$find, $beforeToken, $extraLeft, $extraRight]\n        $this->insertionMap = [\n            'Expr_ArrayDimFetch->dim' => ['[', false, null, null],\n            'ArrayItem->key' => [null, false, null, ' => '],\n            'Expr_ArrowFunction->returnType' => [')', false, ': ', null],\n            'Expr_Closure->returnType' => [')', false, ': ', null],\n            'Expr_Ternary->if' => ['?', false, ' ', ' '],\n            'Expr_Yield->key' => [\\T_YIELD, false, null, ' => '],\n            'Expr_Yield->value' => [\\T_YIELD, false, ' ', null],\n            'Param->type' => [null, false, null, ' '],\n            'Param->default' => [null, false, ' = ', null],\n            'Stmt_Break->num' => [\\T_BREAK, false, ' ', null],\n            'Stmt_Catch->var' => [null, false, ' ', null],\n            'Stmt_ClassMethod->returnType' => [')', false, ': ', null],\n            'Stmt_ClassConst->type' => [\\T_CONST, false, ' ', null],\n            'Stmt_Class->extends' => [null, false, ' extends ', null],\n            'Stmt_Enum->scalarType' => [null, false, ' : ', null],\n            'Stmt_EnumCase->expr' => [null, false, ' = ', null],\n            'Expr_PrintableNewAnonClass->extends' => [null, false, ' extends ', null],\n            'Stmt_Continue->num' => [\\T_CONTINUE, false, ' ', null],\n            'Stmt_Foreach->keyVar' => [\\T_AS, false, null, ' => '],\n            'Stmt_Function->returnType' => [')', false, ': ', null],\n            'Stmt_If->else' => [null, false, ' ', null],\n            'Stmt_Namespace->name' => [\\T_NAMESPACE, false, ' ', null],\n            'Stmt_Property->type' => [\\T_VARIABLE, true, null, ' '],\n            'PropertyItem->default' => [null, false, ' = ', null],\n            'Stmt_Return->expr' => [\\T_RETURN, false, ' ', null],\n            'Stmt_StaticVar->default' => [null, false, ' = ', null],\n            //'Stmt_TraitUseAdaptation_Alias->newName' => [T_AS, false, ' ', null], // TODO\n            'Stmt_TryCatch->finally' => [null, false, ' ', null],\n\n            // 'Expr_Exit->expr': Complicated due to optional ()\n            // 'Stmt_Case->cond': Conversion from default to case\n            // 'Stmt_Class->name': Unclear\n            // 'Stmt_Declare->stmts': Not a proper node\n            // 'Stmt_TraitUseAdaptation_Alias->newModifier': Not a proper node\n        ];\n    }\n\n    protected function initializeListInsertionMap(): void {\n        if (isset($this->listInsertionMap)) {\n            return;\n        }\n\n        $this->listInsertionMap = [\n            // special\n            //'Expr_ShellExec->parts' => '', // TODO These need to be treated more carefully\n            //'Scalar_InterpolatedString->parts' => '',\n            Stmt\\Catch_::class . '->types' => '|',\n            UnionType::class . '->types' => '|',\n            IntersectionType::class . '->types' => '&',\n            Stmt\\If_::class . '->elseifs' => ' ',\n            Stmt\\TryCatch::class . '->catches' => ' ',\n\n            // comma-separated lists\n            Expr\\Array_::class . '->items' => ', ',\n            Expr\\ArrowFunction::class . '->params' => ', ',\n            Expr\\Closure::class . '->params' => ', ',\n            Expr\\Closure::class . '->uses' => ', ',\n            Expr\\FuncCall::class . '->args' => ', ',\n            Expr\\Isset_::class . '->vars' => ', ',\n            Expr\\List_::class . '->items' => ', ',\n            Expr\\MethodCall::class . '->args' => ', ',\n            Expr\\NullsafeMethodCall::class . '->args' => ', ',\n            Expr\\New_::class . '->args' => ', ',\n            PrintableNewAnonClassNode::class . '->args' => ', ',\n            Expr\\StaticCall::class . '->args' => ', ',\n            Stmt\\ClassConst::class . '->consts' => ', ',\n            Stmt\\ClassMethod::class . '->params' => ', ',\n            Stmt\\Class_::class . '->implements' => ', ',\n            Stmt\\Enum_::class . '->implements' => ', ',\n            PrintableNewAnonClassNode::class . '->implements' => ', ',\n            Stmt\\Const_::class . '->consts' => ', ',\n            Stmt\\Declare_::class . '->declares' => ', ',\n            Stmt\\Echo_::class . '->exprs' => ', ',\n            Stmt\\For_::class . '->init' => ', ',\n            Stmt\\For_::class . '->cond' => ', ',\n            Stmt\\For_::class . '->loop' => ', ',\n            Stmt\\Function_::class . '->params' => ', ',\n            Stmt\\Global_::class . '->vars' => ', ',\n            Stmt\\GroupUse::class . '->uses' => ', ',\n            Stmt\\Interface_::class . '->extends' => ', ',\n            Expr\\Match_::class . '->arms' => ', ',\n            Stmt\\Property::class . '->props' => ', ',\n            Stmt\\StaticVar::class . '->vars' => ', ',\n            Stmt\\TraitUse::class . '->traits' => ', ',\n            Stmt\\TraitUseAdaptation\\Precedence::class . '->insteadof' => ', ',\n            Stmt\\Unset_::class .  '->vars' => ', ',\n            Stmt\\UseUse::class . '->uses' => ', ',\n            MatchArm::class . '->conds' => ', ',\n            AttributeGroup::class . '->attrs' => ', ',\n            PropertyHook::class . '->params' => ', ',\n\n            // statement lists\n            Expr\\Closure::class . '->stmts' => \"\\n\",\n            Stmt\\Case_::class . '->stmts' => \"\\n\",\n            Stmt\\Catch_::class . '->stmts' => \"\\n\",\n            Stmt\\Class_::class . '->stmts' => \"\\n\",\n            Stmt\\Enum_::class . '->stmts' => \"\\n\",\n            PrintableNewAnonClassNode::class . '->stmts' => \"\\n\",\n            Stmt\\Interface_::class . '->stmts' => \"\\n\",\n            Stmt\\Trait_::class . '->stmts' => \"\\n\",\n            Stmt\\ClassMethod::class . '->stmts' => \"\\n\",\n            Stmt\\Declare_::class . '->stmts' => \"\\n\",\n            Stmt\\Do_::class . '->stmts' => \"\\n\",\n            Stmt\\ElseIf_::class . '->stmts' => \"\\n\",\n            Stmt\\Else_::class . '->stmts' => \"\\n\",\n            Stmt\\Finally_::class . '->stmts' => \"\\n\",\n            Stmt\\Foreach_::class . '->stmts' => \"\\n\",\n            Stmt\\For_::class . '->stmts' => \"\\n\",\n            Stmt\\Function_::class . '->stmts' => \"\\n\",\n            Stmt\\If_::class . '->stmts' => \"\\n\",\n            Stmt\\Namespace_::class . '->stmts' => \"\\n\",\n            Stmt\\Block::class . '->stmts' => \"\\n\",\n\n            // Attribute groups\n            Stmt\\Class_::class . '->attrGroups' => \"\\n\",\n            Stmt\\Enum_::class . '->attrGroups' => \"\\n\",\n            Stmt\\EnumCase::class . '->attrGroups' => \"\\n\",\n            Stmt\\Interface_::class . '->attrGroups' => \"\\n\",\n            Stmt\\Trait_::class . '->attrGroups' => \"\\n\",\n            Stmt\\Function_::class . '->attrGroups' => \"\\n\",\n            Stmt\\ClassMethod::class . '->attrGroups' => \"\\n\",\n            Stmt\\ClassConst::class . '->attrGroups' => \"\\n\",\n            Stmt\\Property::class . '->attrGroups' => \"\\n\",\n            PrintableNewAnonClassNode::class . '->attrGroups' => ' ',\n            Expr\\Closure::class . '->attrGroups' => ' ',\n            Expr\\ArrowFunction::class . '->attrGroups' => ' ',\n            Param::class . '->attrGroups' => ' ',\n            PropertyHook::class . '->attrGroups' => ' ',\n\n            Stmt\\Switch_::class . '->cases' => \"\\n\",\n            Stmt\\TraitUse::class . '->adaptations' => \"\\n\",\n            Stmt\\TryCatch::class . '->stmts' => \"\\n\",\n            Stmt\\While_::class . '->stmts' => \"\\n\",\n            PropertyHook::class . '->body' => \"\\n\",\n            Stmt\\Property::class . '->hooks' => \"\\n\",\n            Param::class . '->hooks' => \"\\n\",\n\n            // dummy for top-level context\n            'File->stmts' => \"\\n\",\n        ];\n    }\n\n    protected function initializeEmptyListInsertionMap(): void {\n        if (isset($this->emptyListInsertionMap)) {\n            return;\n        }\n\n        // TODO Insertion into empty statement lists.\n\n        // [$find, $extraLeft, $extraRight]\n        $this->emptyListInsertionMap = [\n            Expr\\ArrowFunction::class . '->params' => ['(', '', ''],\n            Expr\\Closure::class . '->uses' => [')', ' use (', ')'],\n            Expr\\Closure::class . '->params' => ['(', '', ''],\n            Expr\\FuncCall::class . '->args' => ['(', '', ''],\n            Expr\\MethodCall::class . '->args' => ['(', '', ''],\n            Expr\\NullsafeMethodCall::class . '->args' => ['(', '', ''],\n            Expr\\New_::class . '->args' => ['(', '', ''],\n            PrintableNewAnonClassNode::class . '->args' => ['(', '', ''],\n            PrintableNewAnonClassNode::class . '->implements' => [null, ' implements ', ''],\n            Expr\\StaticCall::class . '->args' => ['(', '', ''],\n            Stmt\\Class_::class . '->implements' => [null, ' implements ', ''],\n            Stmt\\Enum_::class . '->implements' => [null, ' implements ', ''],\n            Stmt\\ClassMethod::class . '->params' => ['(', '', ''],\n            Stmt\\Interface_::class . '->extends' => [null, ' extends ', ''],\n            Stmt\\Function_::class . '->params' => ['(', '', ''],\n            Stmt\\Interface_::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\Class_::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\Enum_::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\EnumCase::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\ClassConst::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\ClassMethod::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\Function_::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\Property::class . '->attrGroups' => [null, '', \"\\n\"],\n            Stmt\\Trait_::class . '->attrGroups' => [null, '', \"\\n\"],\n            Expr\\ArrowFunction::class . '->attrGroups' => [null, '', ' '],\n            Expr\\Closure::class . '->attrGroups' => [null, '', ' '],\n            Stmt\\Const_::class . '->attrGroups' => [null, '', \"\\n\"],\n            PrintableNewAnonClassNode::class . '->attrGroups' => [\\T_NEW, ' ', ''],\n\n            /* These cannot be empty to start with:\n             * Expr_Isset->vars\n             * Stmt_Catch->types\n             * Stmt_Const->consts\n             * Stmt_ClassConst->consts\n             * Stmt_Declare->declares\n             * Stmt_Echo->exprs\n             * Stmt_Global->vars\n             * Stmt_GroupUse->uses\n             * Stmt_Property->props\n             * Stmt_StaticVar->vars\n             * Stmt_TraitUse->traits\n             * Stmt_TraitUseAdaptation_Precedence->insteadof\n             * Stmt_Unset->vars\n             * Stmt_Use->uses\n             * UnionType->types\n             */\n\n            /* TODO\n             * Stmt_If->elseifs\n             * Stmt_TryCatch->catches\n             * Expr_Array->items\n             * Expr_List->items\n             * Stmt_For->init\n             * Stmt_For->cond\n             * Stmt_For->loop\n             */\n        ];\n    }\n\n    protected function initializeModifierChangeMap(): void {\n        if (isset($this->modifierChangeMap)) {\n            return;\n        }\n\n        $this->modifierChangeMap = [\n            Stmt\\ClassConst::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_CONST],\n            Stmt\\ClassMethod::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_FUNCTION],\n            Stmt\\Class_::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_CLASS],\n            Stmt\\Property::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_VARIABLE],\n            PrintableNewAnonClassNode::class . '->flags' => ['pModifiers', \\T_NEW, \\T_CLASS],\n            Param::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_VARIABLE],\n            PropertyHook::class . '->flags' => ['pModifiers', \\T_WHITESPACE, \\T_STRING],\n            Expr\\Closure::class . '->static' => ['pStatic', \\T_WHITESPACE, \\T_FUNCTION],\n            Expr\\ArrowFunction::class . '->static' => ['pStatic', \\T_WHITESPACE, \\T_FN],\n            //Stmt\\TraitUseAdaptation\\Alias::class . '->newModifier' => 0, // TODO\n        ];\n\n        // List of integer subnodes that are not modifiers:\n        // Expr_Include->type\n        // Stmt_GroupUse->type\n        // Stmt_Use->type\n        // UseItem->type\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/Token.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\n/**\n * A PHP token. On PHP 8.0 this extends from PhpToken.\n */\nclass Token extends Internal\\TokenPolyfill {\n    /** Get (exclusive) zero-based end position of the token. */\n    public function getEndPos(): int {\n        return $this->pos + \\strlen($this->text);\n    }\n\n    /** Get 1-based end line number of the token. */\n    public function getEndLine(): int {\n        return $this->line + \\substr_count($this->text, \"\\n\");\n    }\n}\n","/typephp/vendor/nikic/php-parser/lib/PhpParser/compatibility_tokens.php":"<?php declare(strict_types=1);\n\nnamespace PhpParser;\n\nif (!\\function_exists('PhpParser\\defineCompatibilityTokens')) {\n    function defineCompatibilityTokens(): void {\n        $compatTokens = [\n            // PHP 8.0\n            'T_NAME_QUALIFIED',\n            'T_NAME_FULLY_QUALIFIED',\n            'T_NAME_RELATIVE',\n            'T_MATCH',\n            'T_NULLSAFE_OBJECT_OPERATOR',\n            'T_ATTRIBUTE',\n            // PHP 8.1\n            'T_ENUM',\n            'T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG',\n            'T_AMPERSAND_FOLLOWED_BY_VAR_OR_VARARG',\n            'T_READONLY',\n            // PHP 8.4\n            'T_PROPERTY_C',\n            'T_PUBLIC_SET',\n            'T_PROTECTED_SET',\n            'T_PRIVATE_SET',\n            // PHP 8.5\n            'T_PIPE',\n            'T_VOID_CAST',\n        ];\n\n        // PHP-Parser might be used together with another library that also emulates some or all\n        // of these tokens. Perform a sanity-check that all already defined tokens have been\n        // assigned a unique ID.\n        $usedTokenIds = [];\n        foreach ($compatTokens as $token) {\n            if (\\defined($token)) {\n                $tokenId = \\constant($token);\n                if (!\\is_int($tokenId)) {\n                    throw new \\Error(sprintf(\n                        'Token %s has ID of type %s, should be int. ' .\n                        'You may be using a library with broken token emulation',\n                        $token, \\gettype($tokenId)\n                    ));\n                }\n                $clashingToken = $usedTokenIds[$tokenId] ?? null;\n                if ($clashingToken !== null) {\n                    throw new \\Error(sprintf(\n                        'Token %s has same ID as token %s, ' .\n                        'you may be using a library with broken token emulation',\n                        $token, $clashingToken\n                    ));\n                }\n                $usedTokenIds[$tokenId] = $token;\n            }\n        }\n\n        // Now define any tokens that have not yet been emulated. Try to assign IDs from -1\n        // downwards, but skip any IDs that may already be in use.\n        $newTokenId = -1;\n        foreach ($compatTokens as $token) {\n            if (!\\defined($token)) {\n                while (isset($usedTokenIds[$newTokenId])) {\n                    $newTokenId--;\n                }\n                \\define($token, $newTokenId);\n                $newTokenId--;\n            }\n        }\n    }\n\n    defineCompatibilityTokens();\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/AbstractNodeVisitor.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n */\nabstract class AbstractNodeVisitor implements NodeVisitor // phpcs:ignore SlevomatCodingStandard.Classes.SuperfluousAbstractClassNaming.SuperfluousPrefix\n{\n\n\tpublic function beforeTraverse(array $nodes): ?array\n\t{\n\t\treturn null;\n\t}\n\n\tpublic function enterNode(Node $node)\n\t{\n\t\treturn null;\n\t}\n\n\tpublic function leaveNode(Node $node)\n\t{\n\t\treturn null;\n\t}\n\n\tpublic function afterTraverse(array $nodes): ?array\n\t{\n\t\treturn null;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Attribute.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\nfinal class Attribute\n{\n\n\tpublic const START_LINE = 'startLine';\n\tpublic const END_LINE = 'endLine';\n\n\tpublic const START_INDEX = 'startIndex';\n\tpublic const END_INDEX = 'endIndex';\n\n\tpublic const ORIGINAL_NODE = 'originalNode';\n\n\tpublic const COMMENTS = 'comments';\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Comment.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\nuse function trim;\n\nclass Comment\n{\n\n\tpublic string $text;\n\n\tpublic int $startLine;\n\n\tpublic int $startIndex;\n\n\tpublic function __construct(string $text, int $startLine = -1, int $startIndex = -1)\n\t{\n\t\t$this->text = $text;\n\t\t$this->startLine = $startLine;\n\t\t$this->startIndex = $startIndex;\n\t}\n\n\tpublic function getReformattedText(): string\n\t{\n\t\treturn trim($this->text);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\treturn new self($properties['text'], $properties['startLine'], $properties['startIndex']);\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayItemNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ConstExprArrayItemNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic ?ConstExprNode $key = null;\n\n\tpublic ConstExprNode $value;\n\n\tpublic function __construct(?ConstExprNode $key, ConstExprNode $value)\n\t{\n\t\t$this->key = $key;\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->key !== null) {\n\t\t\treturn sprintf('%s => %s', $this->key, $this->value);\n\n\t\t}\n\n\t\treturn (string) $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['key'], $properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprArrayNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\n\nclass ConstExprArrayNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var ConstExprArrayItemNode[] */\n\tpublic array $items;\n\n\t/**\n\t * @param ConstExprArrayItemNode[] $items\n\t */\n\tpublic function __construct(array $items)\n\t{\n\t\t$this->items = $items;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn '[' . implode(', ', $this->items) . ']';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['items']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFalseNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstExprFalseNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic function __toString(): string\n\t{\n\t\treturn 'false';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self();\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprFloatNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstExprFloatNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $value;\n\n\tpublic function __construct(string $value)\n\t{\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprIntegerNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstExprIntegerNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $value;\n\n\tpublic function __construct(string $value)\n\t{\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\n\ninterface ConstExprNode extends Node\n{\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprNullNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstExprNullNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic function __toString(): string\n\t{\n\t\treturn 'null';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self();\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprStringNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function addcslashes;\nuse function assert;\nuse function dechex;\nuse function ord;\nuse function preg_replace_callback;\nuse function sprintf;\nuse function str_pad;\nuse function strlen;\nuse const STR_PAD_LEFT;\n\nclass ConstExprStringNode implements ConstExprNode\n{\n\n\tpublic const SINGLE_QUOTED = 1;\n\tpublic const DOUBLE_QUOTED = 2;\n\n\tuse NodeAttributes;\n\n\tpublic string $value;\n\n\t/** @var self::SINGLE_QUOTED|self::DOUBLE_QUOTED */\n\tpublic $quoteType;\n\n\t/**\n\t * @param self::SINGLE_QUOTED|self::DOUBLE_QUOTED $quoteType\n\t */\n\tpublic function __construct(string $value, int $quoteType)\n\t{\n\t\t$this->value = $value;\n\t\t$this->quoteType = $quoteType;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->quoteType === self::SINGLE_QUOTED) {\n\t\t\t// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1007\n\t\t\treturn sprintf(\"'%s'\", addcslashes($this->value, '\\'\\\\'));\n\t\t}\n\n\t\t// from https://github.com/nikic/PHP-Parser/blob/0ffddce52d816f72d0efc4d9b02e276d3309ef01/lib/PhpParser/PrettyPrinter/Standard.php#L1010-L1040\n\t\treturn sprintf('\"%s\"', $this->escapeDoubleQuotedString());\n\t}\n\n\tprivate function escapeDoubleQuotedString(): string\n\t{\n\t\t$quote = '\"';\n\t\t$escaped = addcslashes($this->value, \"\\n\\r\\t\\f\\v$\" . $quote . '\\\\');\n\n\t\t// Escape control characters and non-UTF-8 characters.\n\t\t// Regex based on https://stackoverflow.com/a/11709412/385378.\n\t\t$regex = '/(\n              [\\x00-\\x08\\x0E-\\x1F] # Control characters\n            | [\\xC0-\\xC1] # Invalid UTF-8 Bytes\n            | [\\xF5-\\xFF] # Invalid UTF-8 Bytes\n            | \\xE0(?=[\\x80-\\x9F]) # Overlong encoding of prior code point\n            | \\xF0(?=[\\x80-\\x8F]) # Overlong encoding of prior code point\n            | [\\xC2-\\xDF](?![\\x80-\\xBF]) # Invalid UTF-8 Sequence Start\n            | [\\xE0-\\xEF](?![\\x80-\\xBF]{2}) # Invalid UTF-8 Sequence Start\n            | [\\xF0-\\xF4](?![\\x80-\\xBF]{3}) # Invalid UTF-8 Sequence Start\n            | (?<=[\\x00-\\x7F\\xF5-\\xFF])[\\x80-\\xBF] # Invalid UTF-8 Sequence Middle\n            | (?<![\\xC2-\\xDF]|[\\xE0-\\xEF]|[\\xE0-\\xEF][\\x80-\\xBF]|[\\xF0-\\xF4]|[\\xF0-\\xF4][\\x80-\\xBF]|[\\xF0-\\xF4][\\x80-\\xBF]{2})[\\x80-\\xBF] # Overlong Sequence\n            | (?<=[\\xE0-\\xEF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 3 byte sequence\n            | (?<=[\\xF0-\\xF4])[\\x80-\\xBF](?![\\x80-\\xBF]{2}) # Short 4 byte sequence\n            | (?<=[\\xF0-\\xF4][\\x80-\\xBF])[\\x80-\\xBF](?![\\x80-\\xBF]) # Short 4 byte sequence (2)\n        )/x';\n\t\treturn preg_replace_callback($regex, static function ($matches) {\n\t\t\tassert(strlen($matches[0]) === 1);\n\t\t\t$hex = dechex(ord($matches[0]));\n\n\t\t\treturn '\\\\x' . str_pad($hex, 2, '0', STR_PAD_LEFT);\n\t\t}, $escaped);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['value'], $properties['quoteType']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstExprTrueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstExprTrueNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic function __toString(): string\n\t{\n\t\treturn 'true';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self();\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/ConstFetchNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstFetchNode implements ConstExprNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var string class name for class constants or empty string for non-class constants */\n\tpublic string $className;\n\n\tpublic string $name;\n\n\tpublic function __construct(string $className, string $name)\n\t{\n\t\t$this->className = $className;\n\t\t$this->name = $name;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->className === '') {\n\t\t\treturn $this->name;\n\n\t\t}\n\n\t\treturn \"{$this->className}::{$this->name}\";\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['className'], $properties['name']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/ConstExpr/DoctrineConstExprStringNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\ConstExpr;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\nuse function str_replace;\nuse function strlen;\nuse function substr;\n\nclass DoctrineConstExprStringNode extends ConstExprStringNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $value;\n\n\tpublic function __construct(string $value)\n\t{\n\t\tparent::__construct($value, self::DOUBLE_QUOTED);\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn self::escape($this->value);\n\t}\n\n\tpublic static function unescape(string $value): string\n\t{\n\t\t// from https://github.com/doctrine/annotations/blob/a9ec7af212302a75d1f92fa65d3abfbd16245a2a/lib/Doctrine/Common/Annotations/DocLexer.php#L103-L107\n\t\treturn str_replace('\"\"', '\"', substr($value, 1, strlen($value) - 2));\n\t}\n\n\tprivate static function escape(string $value): string\n\t{\n\t\t// from https://github.com/phpstan/phpdoc-parser/issues/205#issuecomment-1662323656\n\t\treturn sprintf('\"%s\"', str_replace('\"', '\"\"', $value));\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Node.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\ninterface Node\n{\n\n\tpublic function __toString(): string;\n\n\t/**\n\t * @param mixed $value\n\t */\n\tpublic function setAttribute(string $key, $value): void;\n\n\tpublic function hasAttribute(string $key): bool;\n\n\t/**\n\t * @return mixed\n\t */\n\tpublic function getAttribute(string $key);\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/NodeAttributes.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\nuse function array_key_exists;\n\ntrait NodeAttributes\n{\n\n\t/** @var array<string, mixed> */\n\tprivate array $attributes = [];\n\n\t/**\n\t * @param mixed $value\n\t */\n\tpublic function setAttribute(string $key, $value): void\n\t{\n\t\tif ($value === null) {\n\t\t\tunset($this->attributes[$key]);\n\t\t\treturn;\n\t\t}\n\t\t$this->attributes[$key] = $value;\n\t}\n\n\tpublic function hasAttribute(string $key): bool\n\t{\n\t\treturn array_key_exists($key, $this->attributes);\n\t}\n\n\t/**\n\t * @return mixed\n\t */\n\tpublic function getAttribute(string $key)\n\t{\n\t\tif ($this->hasAttribute($key)) {\n\t\t\treturn $this->attributes[$key];\n\t\t}\n\n\t\treturn null;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/NodeTraverser.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\nuse LogicException;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function array_keys;\nuse function array_pop;\nuse function array_splice;\nuse function count;\nuse function get_class;\nuse function get_object_vars;\nuse function gettype;\nuse function is_array;\nuse function sprintf;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n */\nfinal class NodeTraverser\n{\n\n\t/**\n\t * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CHILDREN, child nodes\n\t * of the current node will not be traversed for any visitors.\n\t *\n\t * For subsequent visitors enterNode() will still be called on the current\n\t * node and leaveNode() will also be invoked for the current node.\n\t */\n\tpublic const DONT_TRAVERSE_CHILDREN = 1;\n\n\t/**\n\t * If NodeVisitor::enterNode() or NodeVisitor::leaveNode() returns\n\t * STOP_TRAVERSAL, traversal is aborted.\n\t *\n\t * The afterTraverse() method will still be invoked.\n\t */\n\tpublic const STOP_TRAVERSAL = 2;\n\n\t/**\n\t * If NodeVisitor::leaveNode() returns REMOVE_NODE for a node that occurs\n\t * in an array, it will be removed from the array.\n\t *\n\t * For subsequent visitors leaveNode() will still be invoked for the\n\t * removed node.\n\t */\n\tpublic const REMOVE_NODE = 3;\n\n\t/**\n\t * If NodeVisitor::enterNode() returns DONT_TRAVERSE_CURRENT_AND_CHILDREN, child nodes\n\t * of the current node will not be traversed for any visitors.\n\t *\n\t * For subsequent visitors enterNode() will not be called as well.\n\t * leaveNode() will be invoked for visitors that has enterNode() method invoked.\n\t */\n\tpublic const DONT_TRAVERSE_CURRENT_AND_CHILDREN = 4;\n\n\t/** @var list<NodeVisitor> Visitors */\n\tprivate array $visitors = [];\n\n\t/** @var bool Whether traversal should be stopped */\n\tprivate bool $stopTraversal;\n\n\t/**\n\t * @param list<NodeVisitor> $visitors\n\t */\n\tpublic function __construct(array $visitors)\n\t{\n\t\t$this->visitors = $visitors;\n\t}\n\n\t/**\n\t * Traverses an array of nodes using the registered visitors.\n\t *\n\t * @param Node[] $nodes Array of nodes\n\t *\n\t * @return Node[] Traversed array of nodes\n\t */\n\tpublic function traverse(array $nodes): array\n\t{\n\t\t$this->stopTraversal = false;\n\n\t\tforeach ($this->visitors as $visitor) {\n\t\t\t$return = $visitor->beforeTraverse($nodes);\n\t\t\tif ($return === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$nodes = $return;\n\t\t}\n\n\t\t$nodes = $this->traverseArray($nodes);\n\n\t\tforeach ($this->visitors as $visitor) {\n\t\t\t$return = $visitor->afterTraverse($nodes);\n\t\t\tif ($return === null) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$nodes = $return;\n\t\t}\n\n\t\treturn $nodes;\n\t}\n\n\t/**\n\t * Recursively traverse a node.\n\t *\n\t * @param Node $node Node to traverse.\n\t *\n\t * @return Node Result of traversal (may be original node or new one)\n\t */\n\tprivate function traverseNode(Node $node): Node\n\t{\n\t\t$subNodeNames = array_keys(get_object_vars($node));\n\t\tforeach ($subNodeNames as $name) {\n\t\t\t$subNode =& $node->$name;\n\n\t\t\tif (is_array($subNode)) {\n\t\t\t\t$subNode = $this->traverseArray($subNode);\n\t\t\t\tif ($this->stopTraversal) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} elseif ($subNode instanceof Node) {\n\t\t\t\t$traverseChildren = true;\n\t\t\t\t$breakVisitorIndex = null;\n\n\t\t\t\tforeach ($this->visitors as $visitorIndex => $visitor) {\n\t\t\t\t\t$return = $visitor->enterNode($subNode);\n\t\t\t\t\tif ($return === null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($return instanceof Node) {\n\t\t\t\t\t\t$this->ensureReplacementReasonable($subNode, $return);\n\t\t\t\t\t\t$subNode = $return;\n\t\t\t\t\t} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {\n\t\t\t\t\t\t$traverseChildren = false;\n\t\t\t\t\t} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {\n\t\t\t\t\t\t$traverseChildren = false;\n\t\t\t\t\t\t$breakVisitorIndex = $visitorIndex;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} elseif ($return === self::STOP_TRAVERSAL) {\n\t\t\t\t\t\t$this->stopTraversal = true;\n\t\t\t\t\t\tbreak 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new LogicException(\n\t\t\t\t\t\t\t'enterNode() returned invalid value of type ' . gettype($return),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ($traverseChildren) {\n\t\t\t\t\t$subNode = $this->traverseNode($subNode);\n\t\t\t\t\tif ($this->stopTraversal) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tforeach ($this->visitors as $visitorIndex => $visitor) {\n\t\t\t\t\t$return = $visitor->leaveNode($subNode);\n\n\t\t\t\t\tif ($return !== null) {\n\t\t\t\t\t\tif ($return instanceof Node) {\n\t\t\t\t\t\t\t$this->ensureReplacementReasonable($subNode, $return);\n\t\t\t\t\t\t\t$subNode = $return;\n\t\t\t\t\t\t} elseif ($return === self::STOP_TRAVERSAL) {\n\t\t\t\t\t\t\t$this->stopTraversal = true;\n\t\t\t\t\t\t\tbreak 2;\n\t\t\t\t\t\t} elseif (is_array($return)) {\n\t\t\t\t\t\t\tthrow new LogicException(\n\t\t\t\t\t\t\t\t'leaveNode() may only return an array ' .\n\t\t\t\t\t\t\t\t'if the parent structure is an array',\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new LogicException(\n\t\t\t\t\t\t\t\t'leaveNode() returned invalid value of type ' . gettype($return),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($breakVisitorIndex === $visitorIndex) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $node;\n\t}\n\n\t/**\n\t * Recursively traverse array (usually of nodes).\n\t *\n\t * @param mixed[] $nodes Array to traverse\n\t *\n\t * @return mixed[] Result of traversal (may be original array or changed one)\n\t */\n\tprivate function traverseArray(array $nodes): array\n\t{\n\t\t$doNodes = [];\n\n\t\tforeach ($nodes as $i => &$node) {\n\t\t\tif ($node instanceof Node) {\n\t\t\t\t$traverseChildren = true;\n\t\t\t\t$breakVisitorIndex = null;\n\n\t\t\t\tforeach ($this->visitors as $visitorIndex => $visitor) {\n\t\t\t\t\t$return = $visitor->enterNode($node);\n\t\t\t\t\tif ($return === null) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($return instanceof Node) {\n\t\t\t\t\t\t$this->ensureReplacementReasonable($node, $return);\n\t\t\t\t\t\t$node = $return;\n\t\t\t\t\t} elseif (is_array($return)) {\n\t\t\t\t\t\t$doNodes[] = [$i, $return];\n\t\t\t\t\t\tcontinue 2;\n\t\t\t\t\t} elseif ($return === self::REMOVE_NODE) {\n\t\t\t\t\t\t$doNodes[] = [$i, []];\n\t\t\t\t\t\tcontinue 2;\n\t\t\t\t\t} elseif ($return === self::DONT_TRAVERSE_CHILDREN) {\n\t\t\t\t\t\t$traverseChildren = false;\n\t\t\t\t\t} elseif ($return === self::DONT_TRAVERSE_CURRENT_AND_CHILDREN) {\n\t\t\t\t\t\t$traverseChildren = false;\n\t\t\t\t\t\t$breakVisitorIndex = $visitorIndex;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} elseif ($return === self::STOP_TRAVERSAL) {\n\t\t\t\t\t\t$this->stopTraversal = true;\n\t\t\t\t\t\tbreak 2;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new LogicException(\n\t\t\t\t\t\t\t'enterNode() returned invalid value of type ' . gettype($return),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif ($traverseChildren) {\n\t\t\t\t\t$node = $this->traverseNode($node);\n\t\t\t\t\tif ($this->stopTraversal) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tforeach ($this->visitors as $visitorIndex => $visitor) {\n\t\t\t\t\t$return = $visitor->leaveNode($node);\n\n\t\t\t\t\tif ($return !== null) {\n\t\t\t\t\t\tif ($return instanceof Node) {\n\t\t\t\t\t\t\t$this->ensureReplacementReasonable($node, $return);\n\t\t\t\t\t\t\t$node = $return;\n\t\t\t\t\t\t} elseif (is_array($return)) {\n\t\t\t\t\t\t\t$doNodes[] = [$i, $return];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} elseif ($return === self::REMOVE_NODE) {\n\t\t\t\t\t\t\t$doNodes[] = [$i, []];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t} elseif ($return === self::STOP_TRAVERSAL) {\n\t\t\t\t\t\t\t$this->stopTraversal = true;\n\t\t\t\t\t\t\tbreak 2;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tthrow new LogicException(\n\t\t\t\t\t\t\t\t'leaveNode() returned invalid value of type ' . gettype($return),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($breakVisitorIndex === $visitorIndex) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} elseif (is_array($node)) {\n\t\t\t\tthrow new LogicException('Invalid node structure: Contains nested arrays');\n\t\t\t}\n\t\t}\n\n\t\tif (count($doNodes) > 0) {\n\t\t\twhile ([$i, $replace] = array_pop($doNodes)) {\n\t\t\t\tarray_splice($nodes, $i, 1, $replace);\n\t\t\t}\n\t\t}\n\n\t\treturn $nodes;\n\t}\n\n\tprivate function ensureReplacementReasonable(Node $old, Node $new): void\n\t{\n\t\tif ($old instanceof TypeNode && !$new instanceof TypeNode) {\n\t\t\tthrow new LogicException(sprintf('Trying to replace TypeNode with %s', get_class($new)));\n\t\t}\n\n\t\tif ($old instanceof ConstExprNode && !$new instanceof ConstExprNode) {\n\t\t\tthrow new LogicException(sprintf('Trying to replace ConstExprNode with %s', get_class($new)));\n\t\t}\n\n\t\tif ($old instanceof PhpDocChildNode && !$new instanceof PhpDocChildNode) {\n\t\t\tthrow new LogicException(sprintf('Trying to replace PhpDocChildNode with %s', get_class($new)));\n\t\t}\n\n\t\tif ($old instanceof PhpDocTagValueNode && !$new instanceof PhpDocTagValueNode) {\n\t\t\tthrow new LogicException(sprintf('Trying to replace PhpDocTagValueNode with %s', get_class($new)));\n\t\t}\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor/CloningVisitor.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\NodeVisitor;\n\nuse PHPStan\\PhpDocParser\\Ast\\AbstractNodeVisitor;\nuse PHPStan\\PhpDocParser\\Ast\\Attribute;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\n\nfinal class CloningVisitor extends AbstractNodeVisitor\n{\n\n\tpublic function enterNode(Node $originalNode): Node\n\t{\n\t\t$node = clone $originalNode;\n\t\t$node->setAttribute(Attribute::ORIGINAL_NODE, $originalNode);\n\n\t\treturn $node;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/NodeVisitor.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n */\ninterface NodeVisitor\n{\n\n\t/**\n\t * Called once before traversal.\n\t *\n\t * Return value semantics:\n\t *  * null:      $nodes stays as-is\n\t *  * otherwise: $nodes is set to the return value\n\t *\n\t * @param Node[] $nodes Array of nodes\n\t *\n\t * @return Node[]|null Array of nodes\n\t */\n\tpublic function beforeTraverse(array $nodes): ?array;\n\n\t/**\n\t * Called when entering a node.\n\t *\n\t * Return value semantics:\n\t *  * null\n\t *        => $node stays as-is\n\t *  * array (of Nodes)\n\t *        => The return value is merged into the parent array (at the position of the $node)\n\t *  * NodeTraverser::REMOVE_NODE\n\t *        => $node is removed from the parent array\n\t *  * NodeTraverser::DONT_TRAVERSE_CHILDREN\n\t *        => Children of $node are not traversed. $node stays as-is\n\t *  * NodeTraverser::DONT_TRAVERSE_CURRENT_AND_CHILDREN\n\t *        => Further visitors for the current node are skipped, and its children are not\n\t *           traversed. $node stays as-is.\n\t *  * NodeTraverser::STOP_TRAVERSAL\n\t *        => Traversal is aborted. $node stays as-is\n\t *  * otherwise\n\t *        => $node is set to the return value\n\t *\n\t * @param Node $node Node\n\t *\n\t * @return Node|Node[]|NodeTraverser::*|null Replacement node (or special return value)\n\t */\n\tpublic function enterNode(Node $node);\n\n\t/**\n\t * Called when leaving a node.\n\t *\n\t * Return value semantics:\n\t *  * null\n\t *        => $node stays as-is\n\t *  * NodeTraverser::REMOVE_NODE\n\t *        => $node is removed from the parent array\n\t *  * NodeTraverser::STOP_TRAVERSAL\n\t *        => Traversal is aborted. $node stays as-is\n\t *  * array (of Nodes)\n\t *        => The return value is merged into the parent array (at the position of the $node)\n\t *  * otherwise\n\t *        => $node is set to the return value\n\t *\n\t * @param Node $node Node\n\t *\n\t * @return Node|Node[]|NodeTraverser::REMOVE_NODE|NodeTraverser::STOP_TRAVERSAL|null Replacement node (or special return value)\n\t */\n\tpublic function leaveNode(Node $node);\n\n\t/**\n\t * Called once after traversal.\n\t *\n\t * Return value semantics:\n\t *  * null:      $nodes stays as-is\n\t *  * otherwise: $nodes is set to the return value\n\t *\n\t * @param Node[] $nodes Array of nodes\n\t *\n\t * @return Node[]|null Array of nodes\n\t */\n\tpublic function afterTraverse(array $nodes): ?array;\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagMethodValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass AssertTagMethodValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $parameter;\n\n\tpublic string $method;\n\n\tpublic bool $isNegated;\n\n\tpublic bool $isEquality;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $parameter, string $method, bool $isNegated, string $description, bool $isEquality)\n\t{\n\t\t$this->type = $type;\n\t\t$this->parameter = $parameter;\n\t\t$this->method = $method;\n\t\t$this->isNegated = $isNegated;\n\t\t$this->isEquality = $isEquality;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$isNegated = $this->isNegated ? '!' : '';\n\t\t$isEquality = $this->isEquality ? '=' : '';\n\t\treturn trim(\"{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->method}() {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['parameter'], $properties['method'], $properties['isNegated'], $properties['description'], $properties['isEquality']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagPropertyValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass AssertTagPropertyValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $parameter;\n\n\tpublic string $property;\n\n\tpublic bool $isNegated;\n\n\tpublic bool $isEquality;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $parameter, string $property, bool $isNegated, string $description, bool $isEquality)\n\t{\n\t\t$this->type = $type;\n\t\t$this->parameter = $parameter;\n\t\t$this->property = $property;\n\t\t$this->isNegated = $isNegated;\n\t\t$this->isEquality = $isEquality;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$isNegated = $this->isNegated ? '!' : '';\n\t\t$isEquality = $this->isEquality ? '=' : '';\n\t\treturn trim(\"{$isNegated}{$isEquality}{$this->type} {$this->parameter}->{$this->property} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['parameter'], $properties['property'], $properties['isNegated'], $properties['description'], $properties['isEquality']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/AssertTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass AssertTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $parameter;\n\n\tpublic bool $isNegated;\n\n\tpublic bool $isEquality;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $parameter, bool $isNegated, string $description, bool $isEquality)\n\t{\n\t\t$this->type = $type;\n\t\t$this->parameter = $parameter;\n\t\t$this->isNegated = $isNegated;\n\t\t$this->isEquality = $isEquality;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$isNegated = $this->isNegated ? '!' : '';\n\t\t$isEquality = $this->isEquality ? '=' : '';\n\t\treturn trim(\"{$isNegated}{$isEquality}{$this->type} {$this->parameter} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['parameter'], $properties['isNegated'], $properties['description'], $properties['isEquality']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/DeprecatedTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass DeprecatedTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(string $description)\n\t{\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim($this->description);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineAnnotation.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\n\nclass DoctrineAnnotation implements Node\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $name;\n\n\t/** @var list<DoctrineArgument> */\n\tpublic array $arguments;\n\n\t/**\n\t * @param list<DoctrineArgument> $arguments\n\t */\n\tpublic function __construct(string $name, array $arguments)\n\t{\n\t\t$this->name = $name;\n\t\t$this->arguments = $arguments;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$arguments = implode(', ', $this->arguments);\n\t\treturn $this->name . '(' . $arguments . ')';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['name'], $properties['arguments']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArgument.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\n\n/**\n * @phpstan-type ValueType = DoctrineAnnotation|IdentifierTypeNode|DoctrineArray|ConstExprNode\n */\nclass DoctrineArgument implements Node\n{\n\n\tuse NodeAttributes;\n\n\tpublic ?IdentifierTypeNode $key = null;\n\n\t/** @var ValueType */\n\tpublic $value;\n\n\t/**\n\t * @param ValueType $value\n\t */\n\tpublic function __construct(?IdentifierTypeNode $key, $value)\n\t{\n\t\t$this->key = $key;\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->key === null) {\n\t\t\treturn (string) $this->value;\n\t\t}\n\n\t\treturn $this->key . '=' . $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['key'], $properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArray.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\n\nclass DoctrineArray implements Node\n{\n\n\tuse NodeAttributes;\n\n\t/** @var list<DoctrineArrayItem> */\n\tpublic array $items;\n\n\t/**\n\t * @param list<DoctrineArrayItem> $items\n\t */\n\tpublic function __construct(array $items)\n\t{\n\t\t$this->items = $items;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$items = implode(', ', $this->items);\n\n\t\treturn '{' . $items . '}';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['items']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineArrayItem.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\n\n/**\n * @phpstan-import-type ValueType from DoctrineArgument\n * @phpstan-type KeyType = ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode|null\n */\nclass DoctrineArrayItem implements Node\n{\n\n\tuse NodeAttributes;\n\n\t/** @var KeyType */\n\tpublic $key;\n\n\t/** @var ValueType */\n\tpublic $value;\n\n\t/**\n\t * @param KeyType $key\n\t * @param ValueType $value\n\t */\n\tpublic function __construct($key, $value)\n\t{\n\t\t$this->key = $key;\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->key === null) {\n\t\t\treturn (string) $this->value;\n\t\t}\n\n\t\treturn $this->key . '=' . $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['key'], $properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/Doctrine/DoctrineTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode;\nuse function trim;\n\nclass DoctrineTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic DoctrineAnnotation $annotation;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(\n\t\tDoctrineAnnotation $annotation,\n\t\tstring $description\n\t)\n\t{\n\t\t$this->annotation = $annotation;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->annotation} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['annotation'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ExtendsTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse function trim;\n\nclass ExtendsTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic GenericTypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(GenericTypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/GenericTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass GenericTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var string (may be empty) */\n\tpublic string $value;\n\n\tpublic function __construct(string $value)\n\t{\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ImplementsTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse function trim;\n\nclass ImplementsTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic GenericTypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(GenericTypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/InvalidTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Parser\\ParserException;\nuse function sprintf;\nuse function trigger_error;\nuse const E_USER_WARNING;\n\n/**\n * @property ParserException $exception\n */\nclass InvalidTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var string (may be empty) */\n\tpublic string $value;\n\n\t/** @var mixed[] */\n\tprivate array $exceptionArgs;\n\n\tpublic function __construct(string $value, ParserException $exception)\n\t{\n\t\t$this->value = $value;\n\t\t$this->exceptionArgs = [\n\t\t\t$exception->getCurrentTokenValue(),\n\t\t\t$exception->getCurrentTokenType(),\n\t\t\t$exception->getCurrentOffset(),\n\t\t\t$exception->getExpectedTokenType(),\n\t\t\t$exception->getExpectedTokenValue(),\n\t\t\t$exception->getCurrentTokenLine(),\n\t\t];\n\t}\n\n\tpublic function __get(string $name): ?ParserException\n\t{\n\t\tif ($name !== 'exception') {\n\t\t\ttrigger_error(sprintf('Undefined property: %s::$%s', self::class, $name), E_USER_WARNING);\n\t\t\treturn null;\n\t\t}\n\n\t\treturn new ParserException(...$this->exceptionArgs);\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->value;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$exception = new ParserException(...$properties['exceptionArgs']);\n\t\t$instance = new self($properties['value'], $exception);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function count;\nuse function implode;\n\nclass MethodTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic bool $isStatic;\n\n\tpublic ?TypeNode $returnType = null;\n\n\tpublic string $methodName;\n\n\t/** @var TemplateTagValueNode[] */\n\tpublic array $templateTypes;\n\n\t/** @var MethodTagValueParameterNode[] */\n\tpublic array $parameters;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\t/**\n\t * @param MethodTagValueParameterNode[] $parameters\n\t * @param TemplateTagValueNode[] $templateTypes\n\t */\n\tpublic function __construct(bool $isStatic, ?TypeNode $returnType, string $methodName, array $parameters, string $description, array $templateTypes)\n\t{\n\t\t$this->isStatic = $isStatic;\n\t\t$this->returnType = $returnType;\n\t\t$this->methodName = $methodName;\n\t\t$this->parameters = $parameters;\n\t\t$this->description = $description;\n\t\t$this->templateTypes = $templateTypes;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$static = $this->isStatic ? 'static ' : '';\n\t\t$returnType = $this->returnType !== null ? \"{$this->returnType} \" : '';\n\t\t$parameters = implode(', ', $this->parameters);\n\t\t$description = $this->description !== '' ? \" {$this->description}\" : '';\n\t\t$templateTypes = count($this->templateTypes) > 0 ? '<' . implode(', ', $this->templateTypes) . '>' : '';\n\t\treturn \"{$static}{$returnType}{$this->methodName}{$templateTypes}({$parameters}){$description}\";\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['isStatic'], $properties['returnType'], $properties['methodName'], $properties['parameters'], $properties['description'], $properties['templateTypes']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MethodTagValueParameterNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\n\nclass MethodTagValueParameterNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\tpublic ?TypeNode $type = null;\n\n\tpublic bool $isReference;\n\n\tpublic bool $isVariadic;\n\n\tpublic string $parameterName;\n\n\tpublic ?ConstExprNode $defaultValue = null;\n\n\tpublic function __construct(?TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, ?ConstExprNode $defaultValue)\n\t{\n\t\t$this->type = $type;\n\t\t$this->isReference = $isReference;\n\t\t$this->isVariadic = $isVariadic;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->defaultValue = $defaultValue;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$type = $this->type !== null ? \"{$this->type} \" : '';\n\t\t$isReference = $this->isReference ? '&' : '';\n\t\t$isVariadic = $this->isVariadic ? '...' : '';\n\t\t$default = $this->defaultValue !== null ? \" = {$this->defaultValue}\" : '';\n\t\treturn \"{$type}{$isReference}{$isVariadic}{$this->parameterName}{$default}\";\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['isReference'], $properties['isVariadic'], $properties['parameterName'], $properties['defaultValue']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/MixinTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass MixinTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamClosureThisTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass ParamClosureThisTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $parameterName, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamImmediatelyInvokedCallableTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass ParamImmediatelyInvokedCallableTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(string $parameterName, string $description)\n\t{\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamLaterInvokedCallableTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass ParamLaterInvokedCallableTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(string $parameterName, string $description)\n\t{\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamOutTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass ParamOutTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $parameterName, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ParamTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass ParamTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic bool $isReference;\n\n\tpublic bool $isVariadic;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, bool $isVariadic, string $parameterName, string $description, bool $isReference)\n\t{\n\t\t$this->type = $type;\n\t\t$this->isReference = $isReference;\n\t\t$this->isVariadic = $isVariadic;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$reference = $this->isReference ? '&' : '';\n\t\t$variadic = $this->isVariadic ? '...' : '';\n\t\treturn trim(\"{$this->type} {$reference}{$variadic}{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['isVariadic'], $properties['parameterName'], $properties['description'], $properties['isReference']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocChildNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\n\ninterface PhpDocChildNode extends Node\n{\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function array_column;\nuse function array_filter;\nuse function array_map;\nuse function implode;\n\nclass PhpDocNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\t/** @var PhpDocChildNode[] */\n\tpublic array $children;\n\n\t/**\n\t * @param PhpDocChildNode[] $children\n\t */\n\tpublic function __construct(array $children)\n\t{\n\t\t$this->children = $children;\n\t}\n\n\t/**\n\t * @return PhpDocTagNode[]\n\t */\n\tpublic function getTags(): array\n\t{\n\t\treturn array_filter($this->children, static fn (PhpDocChildNode $child): bool => $child instanceof PhpDocTagNode);\n\t}\n\n\t/**\n\t * @return PhpDocTagNode[]\n\t */\n\tpublic function getTagsByName(string $tagName): array\n\t{\n\t\treturn array_filter($this->getTags(), static fn (PhpDocTagNode $tag): bool => $tag->name === $tagName);\n\t}\n\n\t/**\n\t * @return VarTagValueNode[]\n\t */\n\tpublic function getVarTagValues(string $tagName = '@var'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof VarTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ParamTagValueNode[]\n\t */\n\tpublic function getParamTagValues(string $tagName = '@param'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ParamTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return TypelessParamTagValueNode[]\n\t */\n\tpublic function getTypelessParamTagValues(string $tagName = '@param'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof TypelessParamTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ParamImmediatelyInvokedCallableTagValueNode[]\n\t */\n\tpublic function getParamImmediatelyInvokedCallableTagValues(string $tagName = '@param-immediately-invoked-callable'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ParamImmediatelyInvokedCallableTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ParamLaterInvokedCallableTagValueNode[]\n\t */\n\tpublic function getParamLaterInvokedCallableTagValues(string $tagName = '@param-later-invoked-callable'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ParamLaterInvokedCallableTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ParamClosureThisTagValueNode[]\n\t */\n\tpublic function getParamClosureThisTagValues(string $tagName = '@param-closure-this'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ParamClosureThisTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return PureUnlessCallableIsImpureTagValueNode[]\n\t */\n\tpublic function getPureUnlessCallableIsImpureTagValues(string $tagName = '@pure-unless-callable-is-impure'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessCallableIsImpureTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return PureUnlessParameterIsPassedTagValueNode[]\n\t */\n\tpublic function getPureUnlessParameterIsPassedTagValues(string $tagName = '@pure-unless-parameter-passed'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof PureUnlessParameterIsPassedTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return TemplateTagValueNode[]\n\t */\n\tpublic function getTemplateTagValues(string $tagName = '@template'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof TemplateTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ExtendsTagValueNode[]\n\t */\n\tpublic function getExtendsTagValues(string $tagName = '@extends'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ExtendsTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ImplementsTagValueNode[]\n\t */\n\tpublic function getImplementsTagValues(string $tagName = '@implements'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ImplementsTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return UsesTagValueNode[]\n\t */\n\tpublic function getUsesTagValues(string $tagName = '@use'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof UsesTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ReturnTagValueNode[]\n\t */\n\tpublic function getReturnTagValues(string $tagName = '@return'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ReturnTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ThrowsTagValueNode[]\n\t */\n\tpublic function getThrowsTagValues(string $tagName = '@throws'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ThrowsTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return MixinTagValueNode[]\n\t */\n\tpublic function getMixinTagValues(string $tagName = '@mixin'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof MixinTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return RequireExtendsTagValueNode[]\n\t */\n\tpublic function getRequireExtendsTagValues(string $tagName = '@phpstan-require-extends'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof RequireExtendsTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return RequireImplementsTagValueNode[]\n\t */\n\tpublic function getRequireImplementsTagValues(string $tagName = '@phpstan-require-implements'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof RequireImplementsTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return SealedTagValueNode[]\n\t */\n\tpublic function getSealedTagValues(string $tagName = '@phpstan-sealed'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof SealedTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return DeprecatedTagValueNode[]\n\t */\n\tpublic function getDeprecatedTagValues(): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName('@deprecated'), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof DeprecatedTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return PropertyTagValueNode[]\n\t */\n\tpublic function getPropertyTagValues(string $tagName = '@property'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return PropertyTagValueNode[]\n\t */\n\tpublic function getPropertyReadTagValues(string $tagName = '@property-read'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return PropertyTagValueNode[]\n\t */\n\tpublic function getPropertyWriteTagValues(string $tagName = '@property-write'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof PropertyTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return MethodTagValueNode[]\n\t */\n\tpublic function getMethodTagValues(string $tagName = '@method'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof MethodTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return TypeAliasTagValueNode[]\n\t */\n\tpublic function getTypeAliasTagValues(string $tagName = '@phpstan-type'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return TypeAliasImportTagValueNode[]\n\t */\n\tpublic function getTypeAliasImportTagValues(string $tagName = '@phpstan-import-type'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof TypeAliasImportTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return AssertTagValueNode[]\n\t */\n\tpublic function getAssertTagValues(string $tagName = '@phpstan-assert'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return AssertTagPropertyValueNode[]\n\t */\n\tpublic function getAssertPropertyTagValues(string $tagName = '@phpstan-assert'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagPropertyValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return AssertTagMethodValueNode[]\n\t */\n\tpublic function getAssertMethodTagValues(string $tagName = '@phpstan-assert'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof AssertTagMethodValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return SelfOutTagValueNode[]\n\t */\n\tpublic function getSelfOutTypeTagValues(string $tagName = '@phpstan-this-out'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof SelfOutTagValueNode,\n\t\t);\n\t}\n\n\t/**\n\t * @return ParamOutTagValueNode[]\n\t */\n\tpublic function getParamOutTypeTagValues(string $tagName = '@param-out'): array\n\t{\n\t\treturn array_filter(\n\t\t\tarray_column($this->getTagsByName($tagName), 'value'),\n\t\t\tstatic fn (PhpDocTagValueNode $value): bool => $value instanceof ParamOutTagValueNode,\n\t\t);\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$children = array_map(\n\t\t\tstatic function (PhpDocChildNode $child): string {\n\t\t\t\t$s = (string) $child;\n\t\t\t\treturn $s === '' ? '' : ' ' . $s;\n\t\t\t},\n\t\t\t$this->children,\n\t\t);\n\t\treturn \"/**\\n *\" . implode(\"\\n *\", $children) . \"\\n */\";\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['children']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode;\nuse function trim;\n\nclass PhpDocTagNode implements PhpDocChildNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $name;\n\n\tpublic PhpDocTagValueNode $value;\n\n\tpublic function __construct(string $name, PhpDocTagValueNode $value)\n\t{\n\t\t$this->name = $name;\n\t\t$this->value = $value;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->value instanceof DoctrineTagValueNode) {\n\t\t\treturn (string) $this->value;\n\t\t}\n\n\t\treturn trim(\"{$this->name} {$this->value}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['name'], $properties['value']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\n\ninterface PhpDocTagValueNode extends Node\n{\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PhpDocTextNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass PhpDocTextNode implements PhpDocChildNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $text;\n\n\tpublic function __construct(string $text)\n\t{\n\t\t$this->text = $text;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->text;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['text']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PropertyTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass PropertyTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic string $propertyName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $propertyName, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->propertyName = $propertyName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->propertyName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['propertyName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessCallableIsImpureTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass PureUnlessCallableIsImpureTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(string $parameterName, string $description)\n\t{\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/PureUnlessParameterIsPassedTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass PureUnlessParameterIsPassedTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(string $parameterName, string $description)\n\t{\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['parameterName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireExtendsTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass RequireExtendsTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/RequireImplementsTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass RequireImplementsTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ReturnTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass ReturnTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SealedTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass SealedTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/SelfOutTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass SelfOutTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim($this->type . ' ' . $this->description);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TemplateTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass TemplateTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var non-empty-string */\n\tpublic string $name;\n\n\tpublic ?TypeNode $bound;\n\n\tpublic ?TypeNode $default;\n\n\tpublic ?TypeNode $lowerBound;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\t/**\n\t * @param non-empty-string $name\n\t */\n\tpublic function __construct(string $name, ?TypeNode $bound, string $description, ?TypeNode $default = null, ?TypeNode $lowerBound = null)\n\t{\n\t\t$this->name = $name;\n\t\t$this->bound = $bound;\n\t\t$this->lowerBound = $lowerBound;\n\t\t$this->default = $default;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$upperBound = $this->bound !== null ? \" of {$this->bound}\" : '';\n\t\t$lowerBound = $this->lowerBound !== null ? \" super {$this->lowerBound}\" : '';\n\t\t$default = $this->default !== null ? \" = {$this->default}\" : '';\n\t\treturn trim(\"{$this->name}{$upperBound}{$lowerBound}{$default} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['name'], $properties['bound'], $properties['description'], $properties['default'] ?? null, $properties['lowerBound'] ?? null);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/ThrowsTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass ThrowsTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasImportTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse function trim;\n\nclass TypeAliasImportTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $importedAlias;\n\n\tpublic IdentifierTypeNode $importedFrom;\n\n\tpublic ?string $importedAs = null;\n\n\tpublic function __construct(string $importedAlias, IdentifierTypeNode $importedFrom, ?string $importedAs)\n\t{\n\t\t$this->importedAlias = $importedAlias;\n\t\t$this->importedFrom = $importedFrom;\n\t\t$this->importedAs = $importedAs;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\n\t\t\t\"{$this->importedAlias} from {$this->importedFrom}\"\n\t\t\t. ($this->importedAs !== null ? \" as {$this->importedAs}\" : ''),\n\t\t);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['importedAlias'], $properties['importedFrom'], $properties['importedAs']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypeAliasTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass TypeAliasTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $alias;\n\n\tpublic TypeNode $type;\n\n\tpublic function __construct(string $alias, TypeNode $type)\n\t{\n\t\t$this->alias = $alias;\n\t\t$this->type = $type;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->alias} {$this->type}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['alias'], $properties['type']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/TypelessParamTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass TypelessParamTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic bool $isReference;\n\n\tpublic bool $isVariadic;\n\n\tpublic string $parameterName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(bool $isVariadic, string $parameterName, string $description, bool $isReference)\n\t{\n\t\t$this->isReference = $isReference;\n\t\t$this->isVariadic = $isVariadic;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$reference = $this->isReference ? '&' : '';\n\t\t$variadic = $this->isVariadic ? '...' : '';\n\t\treturn trim(\"{$reference}{$variadic}{$this->parameterName} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['isVariadic'], $properties['parameterName'], $properties['description'], $properties['isReference']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/UsesTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse function trim;\n\nclass UsesTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic GenericTypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(GenericTypeNode $type, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"{$this->type} {$this->description}\");\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/PhpDoc/VarTagValueNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\PhpDoc;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse function trim;\n\nclass VarTagValueNode implements PhpDocTagValueNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\t/** @var string (may be empty) */\n\tpublic string $variableName;\n\n\t/** @var string (may be empty) */\n\tpublic string $description;\n\n\tpublic function __construct(TypeNode $type, string $variableName, string $description)\n\t{\n\t\t$this->type = $type;\n\t\t$this->variableName = $variableName;\n\t\t$this->description = $description;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn trim(\"$this->type \" . trim(\"{$this->variableName} {$this->description}\"));\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['variableName'], $properties['description']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeItemNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ArrayShapeItemNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\t/** @var ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null */\n\tpublic $keyName;\n\n\tpublic bool $optional;\n\n\tpublic TypeNode $valueType;\n\n\t/**\n\t * @param ConstExprIntegerNode|ConstExprStringNode|ConstFetchNode|IdentifierTypeNode|null $keyName\n\t */\n\tpublic function __construct($keyName, bool $optional, TypeNode $valueType)\n\t{\n\t\t$this->keyName = $keyName;\n\t\t$this->optional = $optional;\n\t\t$this->valueType = $valueType;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->keyName !== null) {\n\t\t\treturn sprintf(\n\t\t\t\t'%s%s: %s',\n\t\t\t\t(string) $this->keyName,\n\t\t\t\t$this->optional ? '?' : '',\n\t\t\t\t(string) $this->valueType,\n\t\t\t);\n\t\t}\n\n\t\treturn (string) $this->valueType;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['keyName'], $properties['optional'], $properties['valueType']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\n\nclass ArrayShapeNode implements TypeNode\n{\n\n\tpublic const KIND_ARRAY = 'array';\n\tpublic const KIND_LIST = 'list';\n\tpublic const KIND_NON_EMPTY_ARRAY = 'non-empty-array';\n\tpublic const KIND_NON_EMPTY_LIST = 'non-empty-list';\n\n\tuse NodeAttributes;\n\n\t/** @var ArrayShapeItemNode[] */\n\tpublic array $items;\n\n\tpublic bool $sealed;\n\n\t/** @var self::KIND_* */\n\tpublic $kind;\n\n\tpublic ?ArrayShapeUnsealedTypeNode $unsealedType = null;\n\n\t/**\n\t * @param ArrayShapeItemNode[] $items\n\t * @param self::KIND_* $kind\n\t */\n\tprivate function __construct(\n\t\tarray $items,\n\t\tbool $sealed = true,\n\t\t?ArrayShapeUnsealedTypeNode $unsealedType = null,\n\t\tstring $kind = self::KIND_ARRAY\n\t)\n\t{\n\t\t$this->items = $items;\n\t\t$this->sealed = $sealed;\n\t\t$this->unsealedType = $unsealedType;\n\t\t$this->kind = $kind;\n\t}\n\n\t/**\n\t * @param ArrayShapeItemNode[] $items\n\t * @param self::KIND_* $kind\n\t */\n\tpublic static function createSealed(array $items, string $kind = self::KIND_ARRAY): self\n\t{\n\t\treturn new self($items, true, null, $kind);\n\t}\n\n\t/**\n\t * @param ArrayShapeItemNode[] $items\n\t * @param self::KIND_* $kind\n\t */\n\tpublic static function createUnsealed(array $items, ?ArrayShapeUnsealedTypeNode $unsealedType, string $kind = self::KIND_ARRAY): self\n\t{\n\t\treturn new self($items, false, $unsealedType, $kind);\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$items = $this->items;\n\n\t\tif (! $this->sealed) {\n\t\t\t$items[] = '...' . $this->unsealedType;\n\t\t}\n\n\t\treturn $this->kind . '{' . implode(', ', $items) . '}';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['items'], $properties['sealed'], $properties['unsealedType'], $properties['kind']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayShapeUnsealedTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ArrayShapeUnsealedTypeNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $valueType;\n\n\tpublic ?TypeNode $keyType = null;\n\n\tpublic function __construct(TypeNode $valueType, ?TypeNode $keyType)\n\t{\n\t\t$this->valueType = $valueType;\n\t\t$this->keyType = $keyType;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->keyType !== null) {\n\t\t\treturn sprintf('<%s, %s>', $this->keyType, $this->valueType);\n\t\t}\n\t\treturn sprintf('<%s>', $this->valueType);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['valueType'], $properties['keyType']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ArrayTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ArrayTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic function __construct(TypeNode $type)\n\t{\n\t\t$this->type = $type;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif (\n\t\t\t$this->type instanceof CallableTypeNode\n\t\t\t|| $this->type instanceof ConstTypeNode\n\t\t\t|| $this->type instanceof NullableTypeNode\n\t\t) {\n\t\t\treturn '(' . $this->type . ')[]';\n\t\t}\n\n\t\treturn $this->type . '[]';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse function implode;\n\nclass CallableTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic IdentifierTypeNode $identifier;\n\n\t/** @var TemplateTagValueNode[] */\n\tpublic array $templateTypes;\n\n\t/** @var CallableTypeParameterNode[] */\n\tpublic array $parameters;\n\n\tpublic TypeNode $returnType;\n\n\t/**\n\t * @param CallableTypeParameterNode[] $parameters\n\t * @param TemplateTagValueNode[]  $templateTypes\n\t */\n\tpublic function __construct(IdentifierTypeNode $identifier, array $parameters, TypeNode $returnType, array $templateTypes)\n\t{\n\t\t$this->identifier = $identifier;\n\t\t$this->parameters = $parameters;\n\t\t$this->returnType = $returnType;\n\t\t$this->templateTypes = $templateTypes;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$returnType = $this->returnType;\n\t\tif ($returnType instanceof self) {\n\t\t\t$returnType = \"({$returnType})\";\n\t\t}\n\t\t$template = $this->templateTypes !== []\n\t\t\t? '<' . implode(', ', $this->templateTypes) . '>'\n\t\t\t: '';\n\t\t$parameters = implode(', ', $this->parameters);\n\t\treturn \"{$this->identifier}{$template}({$parameters}): {$returnType}\";\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['identifier'], $properties['parameters'], $properties['returnType'], $properties['templateTypes']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/CallableTypeParameterNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function trim;\n\nclass CallableTypeParameterNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic bool $isReference;\n\n\tpublic bool $isVariadic;\n\n\t/** @var string (may be empty) */\n\tpublic string $parameterName;\n\n\tpublic bool $isOptional;\n\n\tpublic function __construct(TypeNode $type, bool $isReference, bool $isVariadic, string $parameterName, bool $isOptional)\n\t{\n\t\t$this->type = $type;\n\t\t$this->isReference = $isReference;\n\t\t$this->isVariadic = $isVariadic;\n\t\t$this->parameterName = $parameterName;\n\t\t$this->isOptional = $isOptional;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$type = \"{$this->type} \";\n\t\t$isReference = $this->isReference ? '&' : '';\n\t\t$isVariadic = $this->isVariadic ? '...' : '';\n\t\t$isOptional = $this->isOptional ? '=' : '';\n\t\treturn trim(\"{$type}{$isReference}{$isVariadic}{$this->parameterName}\") . $isOptional;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['isReference'], $properties['isVariadic'], $properties['parameterName'], $properties['isOptional']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeForParameterNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ConditionalTypeForParameterNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $parameterName;\n\n\tpublic TypeNode $targetType;\n\n\tpublic TypeNode $if;\n\n\tpublic TypeNode $else;\n\n\tpublic bool $negated;\n\n\tpublic function __construct(string $parameterName, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)\n\t{\n\t\t$this->parameterName = $parameterName;\n\t\t$this->targetType = $targetType;\n\t\t$this->if = $if;\n\t\t$this->else = $else;\n\t\t$this->negated = $negated;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn sprintf(\n\t\t\t'(%s %s %s ? %s : %s)',\n\t\t\t$this->parameterName,\n\t\t\t$this->negated ? 'is not' : 'is',\n\t\t\t$this->targetType,\n\t\t\t$this->if,\n\t\t\t$this->else,\n\t\t);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['parameterName'], $properties['targetType'], $properties['if'], $properties['else'], $properties['negated']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConditionalTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ConditionalTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $subjectType;\n\n\tpublic TypeNode $targetType;\n\n\tpublic TypeNode $if;\n\n\tpublic TypeNode $else;\n\n\tpublic bool $negated;\n\n\tpublic function __construct(TypeNode $subjectType, TypeNode $targetType, TypeNode $if, TypeNode $else, bool $negated)\n\t{\n\t\t$this->subjectType = $subjectType;\n\t\t$this->targetType = $targetType;\n\t\t$this->if = $if;\n\t\t$this->else = $else;\n\t\t$this->negated = $negated;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn sprintf(\n\t\t\t'(%s %s %s ? %s : %s)',\n\t\t\t// \"?Foo is Bar ? ... : ...\" reads as a nullable type followed by\n\t\t\t// something else, so the subject keeps the parentheses it was read\n\t\t\t// with\n\t\t\t$this->subjectType instanceof NullableTypeNode\n\t\t\t\t? '(' . $this->subjectType . ')'\n\t\t\t\t: $this->subjectType,\n\t\t\t$this->negated ? 'is not' : 'is',\n\t\t\t$this->targetType,\n\t\t\t$this->if,\n\t\t\t$this->else,\n\t\t);\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['subjectType'], $properties['targetType'], $properties['if'], $properties['else'], $properties['negated']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ConstTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ConstTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic ConstExprNode $constExpr;\n\n\tpublic function __construct(ConstExprNode $constExpr)\n\t{\n\t\t$this->constExpr = $constExpr;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->constExpr->__toString();\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['constExpr']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/GenericTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\nuse function sprintf;\n\nclass GenericTypeNode implements TypeNode\n{\n\n\tpublic const VARIANCE_INVARIANT = 'invariant';\n\tpublic const VARIANCE_COVARIANT = 'covariant';\n\tpublic const VARIANCE_CONTRAVARIANT = 'contravariant';\n\tpublic const VARIANCE_BIVARIANT = 'bivariant';\n\n\tuse NodeAttributes;\n\n\tpublic IdentifierTypeNode $type;\n\n\t/** @var TypeNode[] */\n\tpublic array $genericTypes;\n\n\t/** @var (self::VARIANCE_*)[] */\n\tpublic array $variances;\n\n\t/**\n\t * @param TypeNode[] $genericTypes\n\t * @param (self::VARIANCE_*)[] $variances\n\t */\n\tpublic function __construct(IdentifierTypeNode $type, array $genericTypes, array $variances = [])\n\t{\n\t\t$this->type = $type;\n\t\t$this->genericTypes = $genericTypes;\n\t\t$this->variances = $variances;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$genericTypes = [];\n\n\t\tforeach ($this->genericTypes as $index => $type) {\n\t\t\t$variance = $this->variances[$index] ?? self::VARIANCE_INVARIANT;\n\t\t\tif ($variance === self::VARIANCE_INVARIANT) {\n\t\t\t\t$genericTypes[] = (string) $type;\n\t\t\t} elseif ($variance === self::VARIANCE_BIVARIANT) {\n\t\t\t\t$genericTypes[] = '*';\n\t\t\t} else {\n\t\t\t\t$genericTypes[] = sprintf('%s %s', $variance, $type);\n\t\t\t}\n\t\t}\n\n\t\treturn $this->type . '<' . implode(', ', $genericTypes) . '>';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['genericTypes'], $properties['variances'] ?? []);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/IdentifierTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass IdentifierTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic string $name;\n\n\tpublic function __construct(string $name)\n\t{\n\t\t$this->name = $name;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn $this->name;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['name']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/IntersectionTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function array_map;\nuse function implode;\n\nclass IntersectionTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var TypeNode[] */\n\tpublic array $types;\n\n\t/**\n\t * @param TypeNode[] $types\n\t */\n\tpublic function __construct(array $types)\n\t{\n\t\t$this->types = $types;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn '(' . implode(' & ', array_map(static function (TypeNode $type): string {\n\t\t\tif ($type instanceof NullableTypeNode) {\n\t\t\t\treturn '(' . $type . ')';\n\t\t\t}\n\n\t\t\treturn (string) $type;\n\t\t}, $this->types)) . ')';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['types']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/InvalidTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse PHPStan\\PhpDocParser\\Parser\\ParserException;\n\nclass InvalidTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var mixed[] */\n\tprivate array $exceptionArgs;\n\n\tpublic function __construct(ParserException $exception)\n\t{\n\t\t$this->exceptionArgs = [\n\t\t\t$exception->getCurrentTokenValue(),\n\t\t\t$exception->getCurrentTokenType(),\n\t\t\t$exception->getCurrentOffset(),\n\t\t\t$exception->getExpectedTokenType(),\n\t\t\t$exception->getExpectedTokenValue(),\n\t\t\t$exception->getCurrentTokenLine(),\n\t\t];\n\t}\n\n\tpublic function getException(): ParserException\n\t{\n\t\treturn new ParserException(...$this->exceptionArgs);\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn '*Invalid type*';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$exception = new ParserException(...$properties['exceptionArgs']);\n\t\t$instance = new self($exception);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/NullableTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass NullableTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic function __construct(TypeNode $type)\n\t{\n\t\t$this->type = $type;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->type instanceof self) {\n\t\t\t// \"??Foo\" is no type at all, so the one written inside keeps the\n\t\t\t// parentheses it was read with\n\t\t\treturn '?(' . $this->type . ')';\n\t\t}\n\n\t\treturn '?' . $this->type;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeItemNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function sprintf;\n\nclass ObjectShapeItemNode implements Node\n{\n\n\tuse NodeAttributes;\n\n\t/** @var ConstExprStringNode|IdentifierTypeNode */\n\tpublic $keyName;\n\n\tpublic bool $optional;\n\n\tpublic TypeNode $valueType;\n\n\t/**\n\t * @param ConstExprStringNode|IdentifierTypeNode $keyName\n\t */\n\tpublic function __construct($keyName, bool $optional, TypeNode $valueType)\n\t{\n\t\t$this->keyName = $keyName;\n\t\t$this->optional = $optional;\n\t\t$this->valueType = $valueType;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif ($this->keyName !== null) {\n\t\t\treturn sprintf(\n\t\t\t\t'%s%s: %s',\n\t\t\t\t(string) $this->keyName,\n\t\t\t\t$this->optional ? '?' : '',\n\t\t\t\t(string) $this->valueType,\n\t\t\t);\n\t\t}\n\n\t\treturn (string) $this->valueType;\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['keyName'], $properties['optional'], $properties['valueType']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ObjectShapeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function implode;\n\nclass ObjectShapeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var ObjectShapeItemNode[] */\n\tpublic array $items;\n\n\t/**\n\t * @param ObjectShapeItemNode[] $items\n\t */\n\tpublic function __construct(array $items)\n\t{\n\t\t$this->items = $items;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\t$items = $this->items;\n\n\t\treturn 'object{' . implode(', ', $items) . '}';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['items']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/OffsetAccessTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass OffsetAccessTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic TypeNode $type;\n\n\tpublic TypeNode $offset;\n\n\tpublic function __construct(TypeNode $type, TypeNode $offset)\n\t{\n\t\t$this->type = $type;\n\t\t$this->offset = $offset;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\tif (\n\t\t\t$this->type instanceof CallableTypeNode\n\t\t\t|| $this->type instanceof NullableTypeNode\n\t\t) {\n\t\t\treturn '(' . $this->type . ')[' . $this->offset . ']';\n\t\t}\n\n\t\treturn $this->type . '[' . $this->offset . ']';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['type'], $properties['offset']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/ThisTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\n\nclass ThisTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\tpublic function __toString(): string\n\t{\n\t\treturn '$this';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self();\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/TypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\Node;\n\ninterface TypeNode extends Node\n{\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Ast/Type/UnionTypeNode.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Ast\\Type;\n\nuse PHPStan\\PhpDocParser\\Ast\\NodeAttributes;\nuse function array_map;\nuse function implode;\n\nclass UnionTypeNode implements TypeNode\n{\n\n\tuse NodeAttributes;\n\n\t/** @var TypeNode[] */\n\tpublic array $types;\n\n\t/**\n\t * @param TypeNode[] $types\n\t */\n\tpublic function __construct(array $types)\n\t{\n\t\t$this->types = $types;\n\t}\n\n\tpublic function __toString(): string\n\t{\n\t\treturn '(' . implode(' | ', array_map(static function (TypeNode $type): string {\n\t\t\tif ($type instanceof NullableTypeNode) {\n\t\t\t\treturn '(' . $type . ')';\n\t\t\t}\n\n\t\t\t\treturn (string) $type;\n\t\t}, $this->types)) . ')';\n\t}\n\n\t/**\n\t * @param array<string, mixed> $properties\n\t */\n\tpublic static function __set_state(array $properties): self\n\t{\n\t\t$instance = new self($properties['types']);\n\t\tif (isset($properties['attributes'])) {\n\t\t\tforeach ($properties['attributes'] as $key => $value) {\n\t\t\t\t$instance->setAttribute($key, $value);\n\t\t\t}\n\t\t}\n\t\treturn $instance;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Lexer/Lexer.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Lexer;\n\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse function implode;\nuse function preg_match_all;\n\n/**\n * Implementation based on Nette Tokenizer (New BSD License; https://github.com/nette/tokenizer)\n */\nclass Lexer\n{\n\n\tpublic const TOKEN_REFERENCE = 0;\n\tpublic const TOKEN_UNION = 1;\n\tpublic const TOKEN_INTERSECTION = 2;\n\tpublic const TOKEN_NULLABLE = 3;\n\tpublic const TOKEN_OPEN_PARENTHESES = 4;\n\tpublic const TOKEN_CLOSE_PARENTHESES = 5;\n\tpublic const TOKEN_OPEN_ANGLE_BRACKET = 6;\n\tpublic const TOKEN_CLOSE_ANGLE_BRACKET = 7;\n\tpublic const TOKEN_OPEN_SQUARE_BRACKET = 8;\n\tpublic const TOKEN_CLOSE_SQUARE_BRACKET = 9;\n\tpublic const TOKEN_COMMA = 10;\n\tpublic const TOKEN_VARIADIC = 11;\n\tpublic const TOKEN_DOUBLE_COLON = 12;\n\tpublic const TOKEN_DOUBLE_ARROW = 13;\n\tpublic const TOKEN_EQUAL = 14;\n\tpublic const TOKEN_OPEN_PHPDOC = 15;\n\tpublic const TOKEN_CLOSE_PHPDOC = 16;\n\tpublic const TOKEN_PHPDOC_TAG = 17;\n\tpublic const TOKEN_DOCTRINE_TAG = 18;\n\tpublic const TOKEN_FLOAT = 19;\n\tpublic const TOKEN_INTEGER = 20;\n\tpublic const TOKEN_SINGLE_QUOTED_STRING = 21;\n\tpublic const TOKEN_DOUBLE_QUOTED_STRING = 22;\n\tpublic const TOKEN_DOCTRINE_ANNOTATION_STRING = 23;\n\tpublic const TOKEN_IDENTIFIER = 24;\n\tpublic const TOKEN_THIS_VARIABLE = 25;\n\tpublic const TOKEN_VARIABLE = 26;\n\tpublic const TOKEN_HORIZONTAL_WS = 27;\n\tpublic const TOKEN_PHPDOC_EOL = 28;\n\tpublic const TOKEN_OTHER = 29;\n\tpublic const TOKEN_END = 30;\n\tpublic const TOKEN_COLON = 31;\n\tpublic const TOKEN_WILDCARD = 32;\n\tpublic const TOKEN_OPEN_CURLY_BRACKET = 33;\n\tpublic const TOKEN_CLOSE_CURLY_BRACKET = 34;\n\tpublic const TOKEN_NEGATED = 35;\n\tpublic const TOKEN_ARROW = 36;\n\n\tpublic const TOKEN_COMMENT = 37;\n\n\tpublic const TOKEN_LABELS = [\n\t\tself::TOKEN_REFERENCE => '\\'&\\'',\n\t\tself::TOKEN_UNION => '\\'|\\'',\n\t\tself::TOKEN_INTERSECTION => '\\'&\\'',\n\t\tself::TOKEN_NULLABLE => '\\'?\\'',\n\t\tself::TOKEN_NEGATED => '\\'!\\'',\n\t\tself::TOKEN_OPEN_PARENTHESES => '\\'(\\'',\n\t\tself::TOKEN_CLOSE_PARENTHESES => '\\')\\'',\n\t\tself::TOKEN_OPEN_ANGLE_BRACKET => '\\'<\\'',\n\t\tself::TOKEN_CLOSE_ANGLE_BRACKET => '\\'>\\'',\n\t\tself::TOKEN_OPEN_SQUARE_BRACKET => '\\'[\\'',\n\t\tself::TOKEN_CLOSE_SQUARE_BRACKET => '\\']\\'',\n\t\tself::TOKEN_OPEN_CURLY_BRACKET => '\\'{\\'',\n\t\tself::TOKEN_CLOSE_CURLY_BRACKET => '\\'}\\'',\n\t\tself::TOKEN_COMMA => '\\',\\'',\n\t\tself::TOKEN_COMMENT => '\\'//\\'',\n\t\tself::TOKEN_COLON => '\\':\\'',\n\t\tself::TOKEN_VARIADIC => '\\'...\\'',\n\t\tself::TOKEN_DOUBLE_COLON => '\\'::\\'',\n\t\tself::TOKEN_DOUBLE_ARROW => '\\'=>\\'',\n\t\tself::TOKEN_ARROW => '\\'->\\'',\n\t\tself::TOKEN_EQUAL => '\\'=\\'',\n\t\tself::TOKEN_OPEN_PHPDOC => '\\'/**\\'',\n\t\tself::TOKEN_CLOSE_PHPDOC => '\\'*/\\'',\n\t\tself::TOKEN_PHPDOC_TAG => 'TOKEN_PHPDOC_TAG',\n\t\tself::TOKEN_DOCTRINE_TAG => 'TOKEN_DOCTRINE_TAG',\n\t\tself::TOKEN_PHPDOC_EOL => 'TOKEN_PHPDOC_EOL',\n\t\tself::TOKEN_FLOAT => 'TOKEN_FLOAT',\n\t\tself::TOKEN_INTEGER => 'TOKEN_INTEGER',\n\t\tself::TOKEN_SINGLE_QUOTED_STRING => 'TOKEN_SINGLE_QUOTED_STRING',\n\t\tself::TOKEN_DOUBLE_QUOTED_STRING => 'TOKEN_DOUBLE_QUOTED_STRING',\n\t\tself::TOKEN_DOCTRINE_ANNOTATION_STRING => 'TOKEN_DOCTRINE_ANNOTATION_STRING',\n\t\tself::TOKEN_IDENTIFIER => 'type',\n\t\tself::TOKEN_THIS_VARIABLE => '\\'$this\\'',\n\t\tself::TOKEN_VARIABLE => 'variable',\n\t\tself::TOKEN_HORIZONTAL_WS => 'TOKEN_HORIZONTAL_WS',\n\t\tself::TOKEN_OTHER => 'TOKEN_OTHER',\n\t\tself::TOKEN_END => 'TOKEN_END',\n\t\tself::TOKEN_WILDCARD => '*',\n\t];\n\n\tpublic const VALUE_OFFSET = 0;\n\tpublic const TYPE_OFFSET = 1;\n\tpublic const LINE_OFFSET = 2;\n\n\tprivate ParserConfig $config; // @phpstan-ignore property.onlyWritten\n\n\tprivate ?string $regexp = null;\n\n\tpublic function __construct(ParserConfig $config)\n\t{\n\t\t$this->config = $config;\n\t}\n\n\t/**\n\t * @return list<array{string, int, int}>\n\t */\n\tpublic function tokenize(string $s): array\n\t{\n\t\tif ($this->regexp === null) {\n\t\t\t$this->regexp = $this->generateRegexp();\n\t\t}\n\n\t\t// PREG_PATTERN_ORDER, not PREG_SET_ORDER: it collects the whole PHPDoc\n\t\t// into two arrays instead of allocating one array per token. This only\n\t\t// pays off while the token patterns have no capturing groups, because\n\t\t// every group would get an array of its own, one entry per token.\n\t\tpreg_match_all($this->regexp, $s, $matches);\n\n\t\t$values = $matches[0];\n\t\tif ($values === []) {\n\t\t\treturn [['', self::TOKEN_END, 1]];\n\t\t}\n\n\t\t$marks = $matches['MARK'];\n\n\t\t$tokens = [];\n\t\t$line = 1;\n\t\tforeach ($values as $i => $value) {\n\t\t\t$type = (int) $marks[$i];\n\t\t\t$tokens[] = [$value, $type, $line];\n\t\t\tif ($type !== self::TOKEN_PHPDOC_EOL) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$line++;\n\t\t}\n\n\t\t$tokens[] = ['', self::TOKEN_END, $line];\n\n\t\treturn $tokens;\n\t}\n\n\tprivate function generateRegexp(): string\n\t{\n\t\t// every group in here must be non-capturing, see tokenize()\n\t\t$patterns = [\n\t\t\tself::TOKEN_HORIZONTAL_WS => '[\\\\x09\\\\x20]++',\n\n\t\t\tself::TOKEN_IDENTIFIER => '(?:[\\\\\\\\]?+[a-z_\\\\x80-\\\\xFF][0-9a-z_\\\\x80-\\\\xFF-]*+)++',\n\t\t\tself::TOKEN_THIS_VARIABLE => '\\\\$this(?![0-9a-z_\\\\x80-\\\\xFF])',\n\t\t\tself::TOKEN_VARIABLE => '\\\\$[a-z_\\\\x80-\\\\xFF][0-9a-z_\\\\x80-\\\\xFF]*+',\n\n\t\t\t// '&' followed by TOKEN_VARIADIC, TOKEN_VARIABLE, TOKEN_EQUAL, TOKEN_EQUAL or TOKEN_CLOSE_PARENTHESES\n\t\t\tself::TOKEN_REFERENCE => '&(?=\\\\s*+(?:[,=)]|\\\\.\\\\.\\\\.|(?:\\\\$(?!this(?![0-9a-z_\\\\x80-\\\\xFF])))))',\n\t\t\tself::TOKEN_UNION => '\\\\|',\n\t\t\tself::TOKEN_INTERSECTION => '&',\n\t\t\tself::TOKEN_NULLABLE => '\\\\?',\n\t\t\tself::TOKEN_NEGATED => '!',\n\n\t\t\tself::TOKEN_OPEN_PARENTHESES => '\\\\(',\n\t\t\tself::TOKEN_CLOSE_PARENTHESES => '\\\\)',\n\t\t\tself::TOKEN_OPEN_ANGLE_BRACKET => '<',\n\t\t\tself::TOKEN_CLOSE_ANGLE_BRACKET => '>',\n\t\t\tself::TOKEN_OPEN_SQUARE_BRACKET => '\\\\[',\n\t\t\tself::TOKEN_CLOSE_SQUARE_BRACKET => '\\\\]',\n\t\t\tself::TOKEN_OPEN_CURLY_BRACKET => '\\\\{',\n\t\t\tself::TOKEN_CLOSE_CURLY_BRACKET => '\\\\}',\n\n\t\t\tself::TOKEN_COMMA => ',',\n\t\t\tself::TOKEN_COMMENT => '\\/\\/[^\\\\r\\\\n]*(?=\\n|\\r|\\*/)',\n\t\t\tself::TOKEN_VARIADIC => '\\\\.\\\\.\\\\.',\n\t\t\tself::TOKEN_DOUBLE_COLON => '::',\n\t\t\tself::TOKEN_DOUBLE_ARROW => '=>',\n\t\t\tself::TOKEN_ARROW => '->',\n\t\t\tself::TOKEN_EQUAL => '=',\n\t\t\tself::TOKEN_COLON => ':',\n\n\t\t\tself::TOKEN_OPEN_PHPDOC => '/\\\\*\\\\*(?=\\\\s)\\\\x20?+',\n\t\t\tself::TOKEN_CLOSE_PHPDOC => '\\\\*/',\n\t\t\tself::TOKEN_PHPDOC_TAG => '@(?:[a-z][a-z0-9-\\\\\\\\]+:)?[a-z][a-z0-9-\\\\\\\\]*+',\n\t\t\tself::TOKEN_DOCTRINE_TAG => '@[a-z_\\\\\\\\][a-z0-9_\\:\\\\\\\\]*[a-z_][a-z0-9_]*',\n\t\t\tself::TOKEN_PHPDOC_EOL => '\\\\r?+\\\\n[\\\\x09\\\\x20]*+(?:\\\\*(?!/)\\\\x20?+)?',\n\n\t\t\tself::TOKEN_FLOAT => '[+\\-]?(?:(?:[0-9]++(?:_[0-9]++)*\\\\.[0-9]*+(?:_[0-9]++)*(?:e[+\\-]?[0-9]++(?:_[0-9]++)*)?)|(?:[0-9]*+(?:_[0-9]++)*\\\\.[0-9]++(?:_[0-9]++)*(?:e[+\\-]?[0-9]++(?:_[0-9]++)*)?)|(?:[0-9]++(?:_[0-9]++)*e[+\\-]?[0-9]++(?:_[0-9]++)*))',\n\t\t\tself::TOKEN_INTEGER => '[+\\-]?(?:(?:0b[0-1]++(?:_[0-1]++)*)|(?:0o[0-7]++(?:_[0-7]++)*)|(?:0x[0-9a-f]++(?:_[0-9a-f]++)*)|(?:[0-9]++(?:_[0-9]++)*))',\n\t\t\tself::TOKEN_SINGLE_QUOTED_STRING => '\\'(?:\\\\\\\\[^\\\\r\\\\n]|[^\\'\\\\r\\\\n\\\\\\\\])*+\\'',\n\t\t\tself::TOKEN_DOUBLE_QUOTED_STRING => '\"(?:\\\\\\\\[^\\\\r\\\\n]|[^\"\\\\r\\\\n\\\\\\\\])*+\"',\n\t\t\tself::TOKEN_DOCTRINE_ANNOTATION_STRING => '\"(?:\"\"|[^\"])*+\"',\n\n\t\t\tself::TOKEN_WILDCARD => '\\\\*',\n\n\t\t\t// anything but TOKEN_CLOSE_PHPDOC or TOKEN_HORIZONTAL_WS or TOKEN_EOL\n\t\t\tself::TOKEN_OTHER => '(?:(?!\\\\*/)[^\\\\s])++',\n\t\t];\n\n\t\tforeach ($patterns as $type => &$pattern) {\n\t\t\t$pattern = '(?:' . $pattern . ')(*MARK:' . $type . ')';\n\t\t}\n\n\t\treturn '~' . implode('|', $patterns) . '~Asi';\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/ConstExprParser.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse PHPStan\\PhpDocParser\\Ast;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse function str_replace;\nuse function strtolower;\n\nclass ConstExprParser\n{\n\n\tprivate ParserConfig $config;\n\n\tprivate bool $parseDoctrineStrings;\n\n\tpublic function __construct(\n\t\tParserConfig $config\n\t)\n\t{\n\t\t$this->config = $config;\n\t\t$this->parseDoctrineStrings = false;\n\t}\n\n\t/**\n\t * @internal\n\t */\n\tpublic function toDoctrine(): self\n\t{\n\t\t$self = new self($this->config);\n\t\t$self->parseDoctrineStrings = true;\n\t\treturn $self;\n\t}\n\n\tpublic function parse(TokenIterator $tokens): Ast\\ConstExpr\\ConstExprNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_FLOAT)) {\n\t\t\t$value = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\ConstExpr\\ConstExprFloatNode(str_replace('_', '', $value)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {\n\t\t\t$value = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\ConstExpr\\ConstExprIntegerNode(str_replace('_', '', $value)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\tif ($this->parseDoctrineStrings && $tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {\n\t\t\t$value = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\ConstExpr\\DoctrineConstExprStringNode(Ast\\ConstExpr\\DoctrineConstExprStringNode::unescape($value)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING, Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {\n\t\t\tif ($this->parseDoctrineStrings) {\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {\n\t\t\t\t\tthrow new ParserException(\n\t\t\t\t\t\t$tokens->currentTokenValue(),\n\t\t\t\t\t\t$tokens->currentTokenType(),\n\t\t\t\t\t\t$tokens->currentTokenOffset(),\n\t\t\t\t\t\tLexer::TOKEN_DOUBLE_QUOTED_STRING,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t$tokens->currentTokenLine(),\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\t$value = $tokens->currentTokenValue();\n\t\t\t\t$tokens->next();\n\n\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\t$this->parseDoctrineString($value, $tokens),\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t$value = StringUnescaper::unescapeString($tokens->currentTokenValue());\n\t\t\t$type = $tokens->currentTokenType();\n\t\t\t$tokens->next();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\ConstExpr\\ConstExprStringNode(\n\t\t\t\t\t$value,\n\t\t\t\t\t$type === Lexer::TOKEN_SINGLE_QUOTED_STRING\n\t\t\t\t\t\t? Ast\\ConstExpr\\ConstExprStringNode::SINGLE_QUOTED\n\t\t\t\t\t\t: Ast\\ConstExpr\\ConstExprStringNode::DOUBLE_QUOTED,\n\t\t\t\t),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t$identifier = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\tswitch (strtolower($identifier)) {\n\t\t\t\tcase 'true':\n\t\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\tnew Ast\\ConstExpr\\ConstExprTrueNode(),\n\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t);\n\t\t\t\tcase 'false':\n\t\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\tnew Ast\\ConstExpr\\ConstExprFalseNode(),\n\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t);\n\t\t\t\tcase 'null':\n\t\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\tnew Ast\\ConstExpr\\ConstExprNullNode(),\n\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t);\n\t\t\t\tcase 'array':\n\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);\n\t\t\t\t\treturn $this->parseArray($tokens, Lexer::TOKEN_CLOSE_PARENTHESES, $startIndex);\n\t\t\t}\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t$classConstantName = '';\n\t\t\t\t$lastType = null;\n\t\t\t\twhile (true) {\n\t\t\t\t\tif ($lastType !== Lexer::TOKEN_IDENTIFIER && $tokens->currentTokenType() === Lexer::TOKEN_IDENTIFIER) {\n\t\t\t\t\t\t$classConstantName .= $tokens->currentTokenValue();\n\t\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t\t\t\t\t$lastType = Lexer::TOKEN_IDENTIFIER;\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($lastType !== Lexer::TOKEN_WILDCARD && $tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {\n\t\t\t\t\t\t$classConstantName .= '*';\n\t\t\t\t\t\t$lastType = Lexer::TOKEN_WILDCARD;\n\n\t\t\t\t\t\tif ($tokens->getSkippedHorizontalWhiteSpaceIfAny() !== '') {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($lastType === null) {\n\t\t\t\t\t\t// trigger parse error if nothing valid was consumed\n\t\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_WILDCARD);\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\tnew Ast\\ConstExpr\\ConstFetchNode($identifier, $classConstantName),\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\ConstExpr\\ConstFetchNode('', $identifier),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\n\t\t} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\treturn $this->parseArray($tokens, Lexer::TOKEN_CLOSE_SQUARE_BRACKET, $startIndex);\n\t\t}\n\n\t\tthrow new ParserException(\n\t\t\t$tokens->currentTokenValue(),\n\t\t\t$tokens->currentTokenType(),\n\t\t\t$tokens->currentTokenOffset(),\n\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\tnull,\n\t\t\t$tokens->currentTokenLine(),\n\t\t);\n\t}\n\n\tprivate function parseArray(TokenIterator $tokens, int $endToken, int $startIndex): Ast\\ConstExpr\\ConstExprArrayNode\n\t{\n\t\t$items = [];\n\n\t\t$startLine = $tokens->currentTokenLine();\n\n\t\tif (!$tokens->tryConsumeTokenType($endToken)) {\n\t\t\tdo {\n\t\t\t\t$items[] = $this->parseArrayItem($tokens);\n\t\t\t} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA) && !$tokens->isCurrentTokenType($endToken));\n\t\t\t$tokens->consumeTokenType($endToken);\n\t\t}\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\ConstExpr\\ConstExprArrayNode($items),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * This method is supposed to be called with TokenIterator after reading TOKEN_DOUBLE_QUOTED_STRING and shifting\n\t * to the next token.\n\t */\n\tpublic function parseDoctrineString(string $text, TokenIterator $tokens): Ast\\ConstExpr\\DoctrineConstExprStringNode\n\t{\n\t\t// Because of how Lexer works, a valid Doctrine string\n\t\t// can consist of a sequence of TOKEN_DOUBLE_QUOTED_STRING and TOKEN_DOCTRINE_ANNOTATION_STRING\n\t\twhile ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING, Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {\n\t\t\t$text .= $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\t\t}\n\n\t\treturn new Ast\\ConstExpr\\DoctrineConstExprStringNode(Ast\\ConstExpr\\DoctrineConstExprStringNode::unescape($text));\n\t}\n\n\tprivate function parseArrayItem(TokenIterator $tokens): Ast\\ConstExpr\\ConstExprArrayItemNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t$expr = $this->parse($tokens);\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_ARROW)) {\n\t\t\t$key = $expr;\n\t\t\t$value = $this->parse($tokens);\n\n\t\t} else {\n\t\t\t$key = null;\n\t\t\t$value = $expr;\n\t\t}\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\ConstExpr\\ConstExprArrayItemNode($key, $value),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * @template T of Ast\\ConstExpr\\ConstExprNode\n\t * @param T $node\n\t * @return T\n\t */\n\tprivate function enrichWithAttributes(TokenIterator $tokens, Ast\\ConstExpr\\ConstExprNode $node, int $startLine, int $startIndex): Ast\\ConstExpr\\ConstExprNode\n\t{\n\t\tif ($this->config->useLinesAttributes) {\n\t\t\t$node->setAttribute(Ast\\Attribute::START_LINE, $startLine);\n\t\t\t$node->setAttribute(Ast\\Attribute::END_LINE, $tokens->currentTokenLine());\n\t\t}\n\n\t\tif ($this->config->useIndexAttributes) {\n\t\t\t$node->setAttribute(Ast\\Attribute::START_INDEX, $startIndex);\n\t\t\t$node->setAttribute(Ast\\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());\n\t\t}\n\n\t\treturn $node;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/ParserException.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse Exception;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse function assert;\nuse function json_encode;\nuse function sprintf;\nuse const JSON_INVALID_UTF8_SUBSTITUTE;\nuse const JSON_UNESCAPED_SLASHES;\nuse const JSON_UNESCAPED_UNICODE;\n\nclass ParserException extends Exception\n{\n\n\tprivate string $currentTokenValue;\n\n\tprivate int $currentTokenType;\n\n\tprivate int $currentOffset;\n\n\tprivate int $expectedTokenType;\n\n\tprivate ?string $expectedTokenValue;\n\n\tprivate ?int $currentTokenLine;\n\n\tpublic function __construct(\n\t\tstring $currentTokenValue,\n\t\tint $currentTokenType,\n\t\tint $currentOffset,\n\t\tint $expectedTokenType,\n\t\t?string $expectedTokenValue,\n\t\t?int $currentTokenLine\n\t)\n\t{\n\t\t$this->currentTokenValue = $currentTokenValue;\n\t\t$this->currentTokenType = $currentTokenType;\n\t\t$this->currentOffset = $currentOffset;\n\t\t$this->expectedTokenType = $expectedTokenType;\n\t\t$this->expectedTokenValue = $expectedTokenValue;\n\t\t$this->currentTokenLine = $currentTokenLine;\n\n\t\tparent::__construct(sprintf(\n\t\t\t'Unexpected token %s, expected %s%s at offset %d%s',\n\t\t\t$this->formatValue($currentTokenValue),\n\t\t\tLexer::TOKEN_LABELS[$expectedTokenType],\n\t\t\t$expectedTokenValue !== null ? sprintf(' (%s)', $this->formatValue($expectedTokenValue)) : '',\n\t\t\t$currentOffset,\n\t\t\t$currentTokenLine === null ? '' : sprintf(' on line %d', $currentTokenLine),\n\t\t));\n\t}\n\n\tpublic function getCurrentTokenValue(): string\n\t{\n\t\treturn $this->currentTokenValue;\n\t}\n\n\tpublic function getCurrentTokenType(): int\n\t{\n\t\treturn $this->currentTokenType;\n\t}\n\n\tpublic function getCurrentOffset(): int\n\t{\n\t\treturn $this->currentOffset;\n\t}\n\n\tpublic function getExpectedTokenType(): int\n\t{\n\t\treturn $this->expectedTokenType;\n\t}\n\n\tpublic function getExpectedTokenValue(): ?string\n\t{\n\t\treturn $this->expectedTokenValue;\n\t}\n\n\tpublic function getCurrentTokenLine(): ?int\n\t{\n\t\treturn $this->currentTokenLine;\n\t}\n\n\tprivate function formatValue(string $value): string\n\t{\n\t\t$json = json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);\n\t\tassert($json !== false);\n\n\t\treturn $json;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/PhpDocParser.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse LogicException;\nuse PHPStan\\PhpDocParser\\Ast;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprIntegerNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprStringNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstFetchNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse PHPStan\\ShouldNotHappenException;\nuse function array_key_exists;\nuse function count;\nuse function rtrim;\nuse function str_replace;\nuse function trim;\n\n/**\n * @phpstan-import-type ValueType from Doctrine\\DoctrineArgument as DoctrineValueType\n */\nclass PhpDocParser\n{\n\n\tprivate const DISALLOWED_DESCRIPTION_START_TOKENS = [\n\t\tLexer::TOKEN_UNION,\n\t\tLexer::TOKEN_INTERSECTION,\n\t];\n\n\tprivate ParserConfig $config;\n\n\tprivate TypeParser $typeParser;\n\n\tprivate ConstExprParser $constantExprParser;\n\n\tprivate ConstExprParser $doctrineConstantExprParser;\n\n\tpublic function __construct(\n\t\tParserConfig $config,\n\t\tTypeParser $typeParser,\n\t\tConstExprParser $constantExprParser\n\t)\n\t{\n\t\t$this->config = $config;\n\t\t$this->typeParser = $typeParser;\n\t\t$this->constantExprParser = $constantExprParser;\n\t\t$this->doctrineConstantExprParser = $constantExprParser->toDoctrine();\n\t}\n\n\tpublic function parse(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PHPDOC);\n\t\t$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);\n\n\t\t$children = [];\n\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t$lastChild = $this->parseChild($tokens);\n\t\t\t$children[] = $lastChild;\n\t\t\twhile (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\tif (\n\t\t\t\t\t$lastChild instanceof Ast\\PhpDoc\\PhpDocTagNode\n\t\t\t\t\t&& (\n\t\t\t\t\t\t$lastChild->value instanceof Doctrine\\DoctrineTagValueNode\n\t\t\t\t\t\t|| $lastChild->value instanceof Ast\\PhpDoc\\GenericTagValueNode\n\t\t\t\t\t)\n\t\t\t\t) {\n\t\t\t\t\t$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);\n\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\t$lastChild = $this->parseChild($tokens);\n\t\t\t\t\t$children[] = $lastChild;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\n\t\t\t\t$lastChild = $this->parseChild($tokens);\n\t\t\t\t$children[] = $lastChild;\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PHPDOC);\n\t\t} catch (ParserException $e) {\n\t\t\t$name = '';\n\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t\tif (count($children) > 0) {\n\t\t\t\t$lastChild = $children[count($children) - 1];\n\t\t\t\tif ($lastChild instanceof Ast\\PhpDoc\\PhpDocTagNode) {\n\t\t\t\t\t$name = $lastChild->name;\n\t\t\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$tag = new Ast\\PhpDoc\\PhpDocTagNode(\n\t\t\t\t$name,\n\t\t\t\t$this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\tnew Ast\\PhpDoc\\InvalidTagValueNode($e->getMessage(), $e),\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\t$tokens->forwardToTheEnd();\n\n\t\t\t$comments = $tokens->flushComments();\n\t\t\tif ($comments !== []) {\n\t\t\t\tthrow new LogicException('Comments should already be flushed');\n\t\t\t}\n\n\t\t\treturn $this->enrichWithAttributes($tokens, new Ast\\PhpDoc\\PhpDocNode([$this->enrichWithAttributes($tokens, $tag, $startLine, $startIndex)]), 1, 0);\n\t\t}\n\n\t\t$comments = $tokens->flushComments();\n\t\tif ($comments !== []) {\n\t\t\tthrow new LogicException('Comments should already be flushed');\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, new Ast\\PhpDoc\\PhpDocNode($children), 1, 0);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseChild(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocChildNode\n\t{\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {\n\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t\treturn $this->enrichWithAttributes($tokens, $this->parseTag($tokens), $startLine, $startIndex);\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_TAG)) {\n\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t\t$tag = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\t$tagStartLine = $tokens->currentTokenLine();\n\t\t\t$tagStartIndex = $tokens->currentTokenIndex();\n\n\t\t\treturn $this->enrichWithAttributes($tokens, new Ast\\PhpDoc\\PhpDocTagNode(\n\t\t\t\t$tag,\n\t\t\t\t$this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\t$this->parseDoctrineTagValue($tokens, $tag),\n\t\t\t\t\t$tagStartLine,\n\t\t\t\t\t$tagStartIndex,\n\t\t\t\t),\n\t\t\t), $startLine, $startIndex);\n\t\t}\n\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t$text = $this->parseText($tokens);\n\n\t\treturn $this->enrichWithAttributes($tokens, $text, $startLine, $startIndex);\n\t}\n\n\t/**\n\t * @template T of Ast\\Node\n\t * @param T $tag\n\t * @return T\n\t */\n\tprivate function enrichWithAttributes(TokenIterator $tokens, Ast\\Node $tag, int $startLine, int $startIndex): Ast\\Node\n\t{\n\t\tif ($this->config->useLinesAttributes) {\n\t\t\t$tag->setAttribute(Ast\\Attribute::START_LINE, $startLine);\n\t\t\t$tag->setAttribute(Ast\\Attribute::END_LINE, $tokens->currentTokenLine());\n\t\t}\n\n\t\tif ($this->config->useIndexAttributes) {\n\t\t\t$tag->setAttribute(Ast\\Attribute::START_INDEX, $startIndex);\n\t\t\t$tag->setAttribute(Ast\\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());\n\t\t}\n\n\t\treturn $tag;\n\t}\n\n\tprivate function parseText(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocTextNode\n\t{\n\t\t$text = '';\n\n\t\t$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];\n\n\t\t$savepoint = false;\n\n\t\t// if the next token is EOL, everything below is skipped and empty string is returned\n\t\twhile (true) {\n\t\t\t$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);\n\t\t\t$text .= $tmpText;\n\n\t\t\t// stop if we're not at EOL - meaning it's the end of PHPDoc\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!$savepoint) {\n\t\t\t\t$tokens->pushSavePoint();\n\t\t\t\t$savepoint = true;\n\t\t\t} elseif ($tmpText !== '') {\n\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\t$tokens->pushSavePoint();\n\t\t\t}\n\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$tokens->next();\n\n\t\t\t// if we're at EOL, check what's next\n\t\t\t// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {\n\t\t\t\t$tokens->rollback();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// otherwise if the next is text, continue building the description string\n\n\t\t\t$tokens->dropSavePoint();\n\t\t\t$text .= $tokens->getDetectedNewline() ?? \"\\n\";\n\t\t}\n\n\t\tif ($savepoint) {\n\t\t\t$tokens->rollback();\n\t\t\t$text = rtrim($text, $tokens->getDetectedNewline() ?? \"\\n\");\n\t\t}\n\n\t\treturn new Ast\\PhpDoc\\PhpDocTextNode(trim($text, \" \\t\"));\n\t}\n\n\tprivate function parseOptionalDescriptionAfterDoctrineTag(TokenIterator $tokens): string\n\t{\n\t\t$text = '';\n\n\t\t$endTokens = [Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END];\n\n\t\t$savepoint = false;\n\n\t\t// if the next token is EOL, everything below is skipped and empty string is returned\n\t\twhile (true) {\n\t\t\t$tmpText = $tokens->getSkippedHorizontalWhiteSpaceIfAny() . $tokens->joinUntil(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, Lexer::TOKEN_PHPDOC_EOL, ...$endTokens);\n\t\t\t$text .= $tmpText;\n\n\t\t\t// stop if we're not at EOL - meaning it's the end of PHPDoc\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\tif (!$tokens->isPrecededByHorizontalWhitespace()) {\n\t\t\t\t\treturn trim($text . $this->parseText($tokens)->text, \" \\t\");\n\t\t\t\t}\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG)) {\n\t\t\t\t\t$tokens->pushSavePoint();\n\t\t\t\t\t$child = $this->parseChild($tokens);\n\t\t\t\t\tif ($child instanceof Ast\\PhpDoc\\PhpDocTagNode) {\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t$child->value instanceof Ast\\PhpDoc\\GenericTagValueNode\n\t\t\t\t\t\t\t|| $child->value instanceof Doctrine\\DoctrineTagValueNode\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ($child->value instanceof Ast\\PhpDoc\\InvalidTagValueNode) {\n\t\t\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\t\t\t$tokens->pushSavePoint();\n\t\t\t\t\t\t\t$tokens->next();\n\t\t\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\t\t\treturn trim($text . $this->parseText($tokens)->text, \" \\t\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\treturn trim($text . $this->parseText($tokens)->text, \" \\t\");\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tif (!$savepoint) {\n\t\t\t\t$tokens->pushSavePoint();\n\t\t\t\t$savepoint = true;\n\t\t\t} elseif ($tmpText !== '') {\n\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\t$tokens->pushSavePoint();\n\t\t\t}\n\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$tokens->next();\n\n\t\t\t// if we're at EOL, check what's next\n\t\t\t// if next is a PHPDoc tag, EOL, or end of PHPDoc, stop\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG, ...$endTokens)) {\n\t\t\t\t$tokens->rollback();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t// otherwise if the next is text, continue building the description string\n\n\t\t\t$tokens->dropSavePoint();\n\t\t\t$text .= $tokens->getDetectedNewline() ?? \"\\n\";\n\t\t}\n\n\t\tif ($savepoint) {\n\t\t\t$tokens->rollback();\n\t\t\t$text = rtrim($text, $tokens->getDetectedNewline() ?? \"\\n\");\n\t\t}\n\n\t\treturn trim($text, \" \\t\");\n\t}\n\n\tpublic function parseTag(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocTagNode\n\t{\n\t\t$tag = $tokens->currentTokenValue();\n\t\t$tokens->next();\n\t\t$value = $this->parseTagValue($tokens, $tag);\n\n\t\treturn new Ast\\PhpDoc\\PhpDocTagNode($tag, $value);\n\t}\n\n\tpublic function parseTagValue(TokenIterator $tokens, string $tag): Ast\\PhpDoc\\PhpDocTagValueNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\ttry {\n\t\t\t$tokens->pushSavePoint();\n\n\t\t\tswitch ($tag) {\n\t\t\t\tcase '@param':\n\t\t\t\tcase '@phpstan-param':\n\t\t\t\tcase '@psalm-param':\n\t\t\t\tcase '@phan-param':\n\t\t\t\t\t$tagValue = $this->parseParamTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@param-immediately-invoked-callable':\n\t\t\t\tcase '@phpstan-param-immediately-invoked-callable':\n\t\t\t\t\t$tagValue = $this->parseParamImmediatelyInvokedCallableTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@param-later-invoked-callable':\n\t\t\t\tcase '@phpstan-param-later-invoked-callable':\n\t\t\t\t\t$tagValue = $this->parseParamLaterInvokedCallableTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@param-closure-this':\n\t\t\t\tcase '@phpstan-param-closure-this':\n\t\t\t\t\t$tagValue = $this->parseParamClosureThisTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@pure-unless-callable-is-impure':\n\t\t\t\tcase '@phpstan-pure-unless-callable-is-impure':\n\t\t\t\t\t$tagValue = $this->parsePureUnlessCallableIsImpureTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@pure-unless-parameter-passed':\n\t\t\t\tcase '@phpstan-pure-unless-parameter-passed':\n\t\t\t\t\t$tagValue = $this->parsePureUnlessParameterIsPassed($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@var':\n\t\t\t\tcase '@phpstan-var':\n\t\t\t\tcase '@psalm-var':\n\t\t\t\tcase '@phan-var':\n\t\t\t\t\t$tagValue = $this->parseVarTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@return':\n\t\t\t\tcase '@phpstan-return':\n\t\t\t\tcase '@psalm-return':\n\t\t\t\tcase '@phan-return':\n\t\t\t\tcase '@phan-real-return':\n\t\t\t\t\t$tagValue = $this->parseReturnTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@throws':\n\t\t\t\tcase '@phpstan-throws':\n\t\t\t\t\t$tagValue = $this->parseThrowsTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@mixin':\n\t\t\t\tcase '@phan-mixin':\n\t\t\t\t\t$tagValue = $this->parseMixinTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@psalm-require-extends':\n\t\t\t\tcase '@phpstan-require-extends':\n\t\t\t\t\t$tagValue = $this->parseRequireExtendsTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@psalm-require-implements':\n\t\t\t\tcase '@phpstan-require-implements':\n\t\t\t\t\t$tagValue = $this->parseRequireImplementsTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@psalm-inheritors':\n\t\t\t\tcase '@phpstan-sealed':\n\t\t\t\t\t$tagValue = $this->parseSealedTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@deprecated':\n\t\t\t\t\t$tagValue = $this->parseDeprecatedTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@property':\n\t\t\t\tcase '@property-read':\n\t\t\t\tcase '@property-write':\n\t\t\t\tcase '@phpstan-property':\n\t\t\t\tcase '@phpstan-property-read':\n\t\t\t\tcase '@phpstan-property-write':\n\t\t\t\tcase '@psalm-property':\n\t\t\t\tcase '@psalm-property-read':\n\t\t\t\tcase '@psalm-property-write':\n\t\t\t\tcase '@phan-property':\n\t\t\t\tcase '@phan-property-read':\n\t\t\t\tcase '@phan-property-write':\n\t\t\t\t\t$tagValue = $this->parsePropertyTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@method':\n\t\t\t\tcase '@phpstan-method':\n\t\t\t\tcase '@psalm-method':\n\t\t\t\tcase '@phan-method':\n\t\t\t\t\t$tagValue = $this->parseMethodTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@template':\n\t\t\t\tcase '@phpstan-template':\n\t\t\t\tcase '@psalm-template':\n\t\t\t\tcase '@phan-template':\n\t\t\t\tcase '@template-covariant':\n\t\t\t\tcase '@phpstan-template-covariant':\n\t\t\t\tcase '@psalm-template-covariant':\n\t\t\t\tcase '@template-contravariant':\n\t\t\t\tcase '@phpstan-template-contravariant':\n\t\t\t\tcase '@psalm-template-contravariant':\n\t\t\t\t\t$tagValue = $this->typeParser->parseTemplateTagValue(\n\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\tfn ($tokens) => $this->parseOptionalDescription($tokens, true),\n\t\t\t\t\t);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@extends':\n\t\t\t\tcase '@phpstan-extends':\n\t\t\t\tcase '@phan-extends':\n\t\t\t\tcase '@phan-inherits':\n\t\t\t\tcase '@template-extends':\n\t\t\t\t\t$tagValue = $this->parseExtendsTagValue('@extends', $tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@implements':\n\t\t\t\tcase '@phpstan-implements':\n\t\t\t\tcase '@template-implements':\n\t\t\t\t\t$tagValue = $this->parseExtendsTagValue('@implements', $tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@use':\n\t\t\t\tcase '@phpstan-use':\n\t\t\t\tcase '@template-use':\n\t\t\t\t\t$tagValue = $this->parseExtendsTagValue('@use', $tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@phpstan-type':\n\t\t\t\tcase '@psalm-type':\n\t\t\t\tcase '@phan-type':\n\t\t\t\t\t$tagValue = $this->parseTypeAliasTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@phpstan-import-type':\n\t\t\t\tcase '@psalm-import-type':\n\t\t\t\t\t$tagValue = $this->parseTypeAliasImportTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@phpstan-assert':\n\t\t\t\tcase '@phpstan-assert-if-true':\n\t\t\t\tcase '@phpstan-assert-if-false':\n\t\t\t\tcase '@psalm-assert':\n\t\t\t\tcase '@psalm-assert-if-true':\n\t\t\t\tcase '@psalm-assert-if-false':\n\t\t\t\tcase '@phan-assert':\n\t\t\t\tcase '@phan-assert-if-true':\n\t\t\t\tcase '@phan-assert-if-false':\n\t\t\t\t\t$tagValue = $this->parseAssertTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@phpstan-this-out':\n\t\t\t\tcase '@phpstan-self-out':\n\t\t\t\tcase '@psalm-this-out':\n\t\t\t\tcase '@psalm-self-out':\n\t\t\t\t\t$tagValue = $this->parseSelfOutTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase '@param-out':\n\t\t\t\tcase '@phpstan-param-out':\n\t\t\t\tcase '@psalm-param-out':\n\t\t\t\t\t$tagValue = $this->parseParamOutTagValue($tokens);\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t\t\t\t$tagValue = $this->parseDoctrineTagValue($tokens, $tag);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$tagValue = new Ast\\PhpDoc\\GenericTagValueNode($this->parseOptionalDescriptionAfterDoctrineTag($tokens));\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tokens->dropSavePoint();\n\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\t\t\t$tagValue = new Ast\\PhpDoc\\InvalidTagValueNode($this->parseOptionalDescription($tokens, false), $e);\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, $tagValue, $startLine, $startIndex);\n\t}\n\n\tprivate function parseDoctrineTagValue(TokenIterator $tokens, string $tag): Ast\\PhpDoc\\PhpDocTagValueNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\treturn new Doctrine\\DoctrineTagValueNode(\n\t\t\t$this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineAnnotation($tag, $this->parseDoctrineArguments($tokens, false)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t),\n\t\t\t$this->parseOptionalDescriptionAfterDoctrineTag($tokens),\n\t\t);\n\t}\n\n\t/**\n\t * @return list<Doctrine\\DoctrineArgument>\n\t */\n\tprivate function parseDoctrineArguments(TokenIterator $tokens, bool $deep): array\n\t{\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\treturn [];\n\t\t}\n\n\t\tif (!$deep) {\n\t\t\t$tokens->addEndOfLineToSkippedTokens();\n\t\t}\n\n\t\t$arguments = [];\n\n\t\ttry {\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);\n\n\t\t\tdo {\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t$arguments[] = $this->parseDoctrineArgument($tokens);\n\t\t\t} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));\n\t\t} finally {\n\t\t\tif (!$deep) {\n\t\t\t\t$tokens->removeEndOfLineFromSkippedTokens();\n\t\t\t}\n\t\t}\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\n\t\treturn $arguments;\n\t}\n\n\tprivate function parseDoctrineArgument(TokenIterator $tokens): Doctrine\\DoctrineArgument\n\t{\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\ttry {\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$currentValue = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t\t$key = $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew IdentifierTypeNode($currentValue),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_EQUAL);\n\n\t\t\t$value = $this->parseDoctrineArgumentValue($tokens);\n\n\t\t\t$tokens->dropSavePoint();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArgument($key, $value),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArgument(null, $this->parseDoctrineArgumentValue($tokens)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @return DoctrineValueType\n\t */\n\tprivate function parseDoctrineArgumentValue(TokenIterator $tokens)\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_TAG, Lexer::TOKEN_DOCTRINE_TAG)) {\n\t\t\t$name = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineAnnotation($name, $this->parseDoctrineArguments($tokens, true)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET)) {\n\t\t\t$items = [];\n\t\t\tdo {\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t$items[] = $this->parseDoctrineArrayItem($tokens);\n\t\t\t} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));\n\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArray($items),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\n\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t$tokens->pushSavePoint(); // because of ConstFetchNode\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t$identifier = $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\Type\\IdentifierTypeNode($currentTokenValue),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\treturn $identifier;\n\t\t\t}\n\n\t\t\t$tokens->rollback(); // because of ConstFetchNode\n\t\t} else {\n\t\t\t$tokens->dropSavePoint(); // because of ConstFetchNode\n\t\t}\n\n\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t$currentTokenType = $tokens->currentTokenType();\n\t\t$currentTokenOffset = $tokens->currentTokenOffset();\n\t\t$currentTokenLine = $tokens->currentTokenLine();\n\n\t\ttry {\n\t\t\t$constExpr = $this->doctrineConstantExprParser->parse($tokens);\n\t\t\tif ($constExpr instanceof Ast\\ConstExpr\\ConstExprArrayNode) {\n\t\t\t\tthrow new ParserException(\n\t\t\t\t\t$currentTokenValue,\n\t\t\t\t\t$currentTokenType,\n\t\t\t\t\t$currentTokenOffset,\n\t\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\t\tnull,\n\t\t\t\t\t$currentTokenLine,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn $constExpr;\n\t\t} catch (LogicException $e) {\n\t\t\tthrow new ParserException(\n\t\t\t\t$currentTokenValue,\n\t\t\t\t$currentTokenType,\n\t\t\t\t$currentTokenOffset,\n\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\tnull,\n\t\t\t\t$currentTokenLine,\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate function parseDoctrineArrayItem(TokenIterator $tokens): Doctrine\\DoctrineArrayItem\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\ttry {\n\t\t\t$tokens->pushSavePoint();\n\n\t\t\t$key = $this->parseDoctrineArrayKey($tokens);\n\t\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {\n\t\t\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COLON)) {\n\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_EQUAL); // will throw exception\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t$value = $this->parseDoctrineArgumentValue($tokens);\n\n\t\t\t$tokens->dropSavePoint();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArrayItem($key, $value),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Doctrine\\DoctrineArrayItem(null, $this->parseDoctrineArgumentValue($tokens)),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @return ConstExprIntegerNode|ConstExprStringNode|IdentifierTypeNode|ConstFetchNode\n\t */\n\tprivate function parseDoctrineArrayKey(TokenIterator $tokens)\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOCTRINE_ANNOTATION_STRING)) {\n\t\t\t$key = $this->doctrineConstantExprParser->parseDoctrineString($tokens->currentTokenValue(), $tokens);\n\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\\ConstExpr\\ConstExprStringNode::SINGLE_QUOTED);\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {\n\t\t\t$value = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\t\t\t$key = $this->doctrineConstantExprParser->parseDoctrineString($value, $tokens);\n\n\t\t} else {\n\t\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t\t$tokens->pushSavePoint(); // because of ConstFetchNode\n\t\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\tthrow new ParserException(\n\t\t\t\t\t$tokens->currentTokenValue(),\n\t\t\t\t\t$tokens->currentTokenType(),\n\t\t\t\t\t$tokens->currentTokenOffset(),\n\t\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\t\tnull,\n\t\t\t\t\t$tokens->currentTokenLine(),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t$tokens->dropSavePoint();\n\n\t\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\tnew IdentifierTypeNode($currentTokenValue),\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t$tokens->rollback();\n\t\t\t$constExpr = $this->doctrineConstantExprParser->parse($tokens);\n\t\t\tif (!$constExpr instanceof Ast\\ConstExpr\\ConstFetchNode) {\n\t\t\t\tthrow new ParserException(\n\t\t\t\t\t$tokens->currentTokenValue(),\n\t\t\t\t\t$tokens->currentTokenType(),\n\t\t\t\t\t$tokens->currentTokenOffset(),\n\t\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\t\tnull,\n\t\t\t\t\t$tokens->currentTokenLine(),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn $constExpr;\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);\n\t}\n\n\t/**\n\t * @return Ast\\PhpDoc\\ParamTagValueNode|Ast\\PhpDoc\\TypelessParamTagValueNode\n\t */\n\tprivate function parseParamTagValue(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocTagValueNode\n\t{\n\t\tif (\n\t\t\t$tokens->isCurrentTokenType(Lexer::TOKEN_REFERENCE, Lexer::TOKEN_VARIADIC, Lexer::TOKEN_VARIABLE)\n\t\t) {\n\t\t\t$type = null;\n\t\t} else {\n\t\t\t$type = $this->typeParser->parse($tokens);\n\t\t}\n\n\t\t$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);\n\t\t$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\tif ($type !== null) {\n\t\t\treturn new Ast\\PhpDoc\\ParamTagValueNode($type, $isVariadic, $parameterName, $description, $isReference);\n\t\t}\n\n\t\treturn new Ast\\PhpDoc\\TypelessParamTagValueNode($isVariadic, $parameterName, $description, $isReference);\n\t}\n\n\tprivate function parseParamImmediatelyInvokedCallableTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode\n\t{\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode($parameterName, $description);\n\t}\n\n\tprivate function parseParamLaterInvokedCallableTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode\n\t{\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode($parameterName, $description);\n\t}\n\n\tprivate function parseParamClosureThisTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ParamClosureThisTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\ParamClosureThisTagValueNode($type, $parameterName, $description);\n\t}\n\n\tprivate function parsePureUnlessCallableIsImpureTagValue(TokenIterator $tokens): Ast\\PhpDoc\\PureUnlessCallableIsImpureTagValueNode\n\t{\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\PureUnlessCallableIsImpureTagValueNode($parameterName, $description);\n\t}\n\n\tprivate function parsePureUnlessParameterIsPassed(TokenIterator $tokens): Ast\\PhpDoc\\PureUnlessParameterIsPassedTagValueNode\n\t{\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\PureUnlessParameterIsPassedTagValueNode($parameterName, $description);\n\t}\n\n\tprivate function parseVarTagValue(TokenIterator $tokens): Ast\\PhpDoc\\VarTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$variableName = $this->parseOptionalVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, $variableName === '');\n\t\treturn new Ast\\PhpDoc\\VarTagValueNode($type, $variableName, $description);\n\t}\n\n\tprivate function parseReturnTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ReturnTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\ReturnTagValueNode($type, $description);\n\t}\n\n\tprivate function parseThrowsTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ThrowsTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\ThrowsTagValueNode($type, $description);\n\t}\n\n\tprivate function parseMixinTagValue(TokenIterator $tokens): Ast\\PhpDoc\\MixinTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\MixinTagValueNode($type, $description);\n\t}\n\n\tprivate function parseRequireExtendsTagValue(TokenIterator $tokens): Ast\\PhpDoc\\RequireExtendsTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\RequireExtendsTagValueNode($type, $description);\n\t}\n\n\tprivate function parseRequireImplementsTagValue(TokenIterator $tokens): Ast\\PhpDoc\\RequireImplementsTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\RequireImplementsTagValueNode($type, $description);\n\t}\n\n\tprivate function parseSealedTagValue(TokenIterator $tokens): Ast\\PhpDoc\\SealedTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\t\treturn new Ast\\PhpDoc\\SealedTagValueNode($type, $description);\n\t}\n\n\tprivate function parseDeprecatedTagValue(TokenIterator $tokens): Ast\\PhpDoc\\DeprecatedTagValueNode\n\t{\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\t\treturn new Ast\\PhpDoc\\DeprecatedTagValueNode($description);\n\t}\n\n\tprivate function parsePropertyTagValue(TokenIterator $tokens): Ast\\PhpDoc\\PropertyTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\t\treturn new Ast\\PhpDoc\\PropertyTagValueNode($type, $parameterName, $description);\n\t}\n\n\tprivate function parseMethodTagValue(TokenIterator $tokens): Ast\\PhpDoc\\MethodTagValueNode\n\t{\n\t\t$staticKeywordOrReturnTypeOrMethodName = $this->typeParser->parse($tokens);\n\n\t\tif ($staticKeywordOrReturnTypeOrMethodName instanceof Ast\\Type\\IdentifierTypeNode && $staticKeywordOrReturnTypeOrMethodName->name === 'static') {\n\t\t\t$isStatic = true;\n\t\t\t$returnTypeOrMethodName = $this->typeParser->parse($tokens);\n\n\t\t} else {\n\t\t\t$isStatic = false;\n\t\t\t$returnTypeOrMethodName = $staticKeywordOrReturnTypeOrMethodName;\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t$returnType = $returnTypeOrMethodName;\n\t\t\t$methodName = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\n\t\t} elseif ($returnTypeOrMethodName instanceof Ast\\Type\\IdentifierTypeNode) {\n\t\t\t$returnType = $isStatic ? $staticKeywordOrReturnTypeOrMethodName : null;\n\t\t\t$methodName = $returnTypeOrMethodName->name;\n\t\t\t$isStatic = false;\n\n\t\t} else {\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER); // will throw exception\n\t\t\texit;\n\t\t}\n\n\t\t$templateTypes = [];\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {\n\t\t\tdo {\n\t\t\t\t$startLine = $tokens->currentTokenLine();\n\t\t\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t\t\t$templateTypes[] = $this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\t$this->typeParser->parseTemplateTagValue($tokens),\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t);\n\t\t\t} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);\n\t\t}\n\n\t\t$parameters = [];\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {\n\t\t\t$parameters[] = $this->parseMethodTagValueParameter($tokens);\n\t\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {\n\t\t\t\t$parameters[] = $this->parseMethodTagValueParameter($tokens);\n\t\t\t}\n\t\t}\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\t\treturn new Ast\\PhpDoc\\MethodTagValueNode($isStatic, $returnType, $methodName, $parameters, $description, $templateTypes);\n\t}\n\n\tprivate function parseMethodTagValueParameter(TokenIterator $tokens): Ast\\PhpDoc\\MethodTagValueParameterNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tswitch ($tokens->currentTokenType()) {\n\t\t\tcase Lexer::TOKEN_IDENTIFIER:\n\t\t\tcase Lexer::TOKEN_OPEN_PARENTHESES:\n\t\t\tcase Lexer::TOKEN_NULLABLE:\n\t\t\t\t$parameterType = $this->typeParser->parse($tokens);\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\t$parameterType = null;\n\t\t}\n\n\t\t$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);\n\t\t$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);\n\n\t\t$parameterName = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL)) {\n\t\t\t$defaultValue = $this->constantExprParser->parse($tokens);\n\n\t\t} else {\n\t\t\t$defaultValue = null;\n\t\t}\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\PhpDoc\\MethodTagValueParameterNode($parameterType, $isReference, $isVariadic, $parameterName, $defaultValue),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\tprivate function parseExtendsTagValue(string $tagName, TokenIterator $tokens): Ast\\PhpDoc\\PhpDocTagValueNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t$baseType = new IdentifierTypeNode($tokens->currentTokenValue());\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t$type = $this->typeParser->parseGeneric(\n\t\t\t$tokens,\n\t\t\t$this->typeParser->enrichWithAttributes($tokens, $baseType, $startLine, $startIndex),\n\t\t);\n\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\n\t\tswitch ($tagName) {\n\t\t\tcase '@extends':\n\t\t\t\treturn new Ast\\PhpDoc\\ExtendsTagValueNode($type, $description);\n\t\t\tcase '@implements':\n\t\t\t\treturn new Ast\\PhpDoc\\ImplementsTagValueNode($type, $description);\n\t\t\tcase '@use':\n\t\t\t\treturn new Ast\\PhpDoc\\UsesTagValueNode($type, $description);\n\t\t}\n\n\t\tthrow new ShouldNotHappenException();\n\t}\n\n\tprivate function parseTypeAliasTagValue(TokenIterator $tokens): Ast\\PhpDoc\\TypeAliasTagValueNode\n\t{\n\t\t$alias = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t// support phan-type/psalm-type syntax\n\t\t$tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);\n\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\ttry {\n\t\t\t$type = $this->typeParser->parse($tokens);\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PHPDOC)) {\n\t\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {\n\t\t\t\t\tthrow new ParserException(\n\t\t\t\t\t\t$tokens->currentTokenValue(),\n\t\t\t\t\t\t$tokens->currentTokenType(),\n\t\t\t\t\t\t$tokens->currentTokenOffset(),\n\t\t\t\t\t\tLexer::TOKEN_PHPDOC_EOL,\n\t\t\t\t\t\tnull,\n\t\t\t\t\t\t$tokens->currentTokenLine(),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new Ast\\PhpDoc\\TypeAliasTagValueNode($alias, $type);\n\t\t} catch (ParserException $e) {\n\t\t\t$this->parseOptionalDescription($tokens, false);\n\t\t\treturn new Ast\\PhpDoc\\TypeAliasTagValueNode(\n\t\t\t\t$alias,\n\t\t\t\t$this->enrichWithAttributes($tokens, new Ast\\Type\\InvalidTypeNode($e), $startLine, $startIndex),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate function parseTypeAliasImportTagValue(TokenIterator $tokens): Ast\\PhpDoc\\TypeAliasImportTagValueNode\n\t{\n\t\t$importedAlias = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'from');\n\n\t\t$identifierStartLine = $tokens->currentTokenLine();\n\t\t$identifierStartIndex = $tokens->currentTokenIndex();\n\t\t$importedFrom = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t$importedFromType = $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew IdentifierTypeNode($importedFrom),\n\t\t\t$identifierStartLine,\n\t\t\t$identifierStartIndex,\n\t\t);\n\n\t\t$importedAs = null;\n\t\tif ($tokens->tryConsumeTokenValue('as')) {\n\t\t\t$importedAs = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t}\n\n\t\treturn new Ast\\PhpDoc\\TypeAliasImportTagValueNode($importedAlias, $importedFromType, $importedAs);\n\t}\n\n\t/**\n\t * @return Ast\\PhpDoc\\AssertTagValueNode|Ast\\PhpDoc\\AssertTagPropertyValueNode|Ast\\PhpDoc\\AssertTagMethodValueNode\n\t */\n\tprivate function parseAssertTagValue(TokenIterator $tokens): Ast\\PhpDoc\\PhpDocTagValueNode\n\t{\n\t\t$isNegated = $tokens->tryConsumeTokenType(Lexer::TOKEN_NEGATED);\n\t\t$isEquality = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$parameter = $this->parseAssertParameter($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\tif (array_key_exists('method', $parameter)) {\n\t\t\treturn new Ast\\PhpDoc\\AssertTagMethodValueNode($type, $parameter['parameter'], $parameter['method'], $isNegated, $description, $isEquality);\n\t\t} elseif (array_key_exists('property', $parameter)) {\n\t\t\treturn new Ast\\PhpDoc\\AssertTagPropertyValueNode($type, $parameter['parameter'], $parameter['property'], $isNegated, $description, $isEquality);\n\t\t}\n\n\t\treturn new Ast\\PhpDoc\\AssertTagValueNode($type, $parameter['parameter'], $isNegated, $description, $isEquality);\n\t}\n\n\t/**\n\t * @return array{parameter: string}|array{parameter: string, property: string}|array{parameter: string, method: string}\n\t */\n\tprivate function parseAssertParameter(TokenIterator $tokens): array\n\t{\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {\n\t\t\t$parameter = '$this';\n\t\t\t$tokens->next();\n\t\t} else {\n\t\t\t$parameter = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_ARROW)) {\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_ARROW);\n\n\t\t\t$propertyOrMethod = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\n\t\t\t\treturn ['parameter' => $parameter, 'method' => $propertyOrMethod];\n\t\t\t}\n\n\t\t\treturn ['parameter' => $parameter, 'property' => $propertyOrMethod];\n\t\t}\n\n\t\treturn ['parameter' => $parameter];\n\t}\n\n\tprivate function parseSelfOutTagValue(TokenIterator $tokens): Ast\\PhpDoc\\SelfOutTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, true);\n\n\t\treturn new Ast\\PhpDoc\\SelfOutTagValueNode($type, $description);\n\t}\n\n\tprivate function parseParamOutTagValue(TokenIterator $tokens): Ast\\PhpDoc\\ParamOutTagValueNode\n\t{\n\t\t$type = $this->typeParser->parse($tokens);\n\t\t$parameterName = $this->parseRequiredVariableName($tokens);\n\t\t$description = $this->parseOptionalDescription($tokens, false);\n\n\t\treturn new Ast\\PhpDoc\\ParamOutTagValueNode($type, $parameterName, $description);\n\t}\n\n\tprivate function parseOptionalVariableName(TokenIterator $tokens): string\n\t{\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {\n\t\t\t$parameterName = $tokens->currentTokenValue();\n\t\t\t$tokens->next();\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_THIS_VARIABLE)) {\n\t\t\t$parameterName = '$this';\n\t\t\t$tokens->next();\n\n\t\t} else {\n\t\t\t$parameterName = '';\n\t\t}\n\n\t\treturn $parameterName;\n\t}\n\n\tprivate function parseRequiredVariableName(TokenIterator $tokens): string\n\t{\n\t\t$parameterName = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);\n\n\t\treturn $parameterName;\n\t}\n\n\t/**\n\t * @param bool $limitStartToken true should be used when the description immediately follows a parsed type\n\t */\n\tprivate function parseOptionalDescription(TokenIterator $tokens, bool $limitStartToken): string\n\t{\n\t\tif ($limitStartToken) {\n\t\t\tforeach (self::DISALLOWED_DESCRIPTION_START_TOKENS as $disallowedStartToken) {\n\t\t\t\tif (!$tokens->isCurrentTokenType($disallowedStartToken)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_OTHER); // will throw exception\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\t!$tokens->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL, Lexer::TOKEN_CLOSE_PHPDOC, Lexer::TOKEN_END)\n\t\t\t\t&& !$tokens->isPrecededByHorizontalWhitespace()\n\t\t\t) {\n\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_HORIZONTAL_WS); // will throw exception\n\t\t\t}\n\t\t}\n\n\t\treturn $this->parseText($tokens)->text;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/StringUnescaper.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse PHPStan\\ShouldNotHappenException;\nuse function chr;\nuse function hexdec;\nuse function octdec;\nuse function preg_replace_callback;\nuse function str_replace;\nuse function substr;\n\nclass StringUnescaper\n{\n\n\tprivate const REPLACEMENTS = [\n\t\t'\\\\' => '\\\\',\n\t\t'n' => \"\\n\",\n\t\t'r' => \"\\r\",\n\t\t't' => \"\\t\",\n\t\t'f' => \"\\f\",\n\t\t'v' => \"\\v\",\n\t\t'e' => \"\\x1B\",\n\t];\n\n\tpublic static function unescapeString(string $string): string\n\t{\n\t\t$quote = $string[0];\n\n\t\tif ($quote === '\\'') {\n\t\t\treturn str_replace(\n\t\t\t\t['\\\\\\\\', '\\\\\\''],\n\t\t\t\t['\\\\', '\\''],\n\t\t\t\tsubstr($string, 1, -1),\n\t\t\t);\n\t\t}\n\n\t\treturn self::parseEscapeSequences(substr($string, 1, -1), '\"');\n\t}\n\n\t/**\n\t * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L90-L130\n\t */\n\tprivate static function parseEscapeSequences(string $str, string $quote): string\n\t{\n\t\t$str = str_replace('\\\\' . $quote, $quote, $str);\n\n\t\treturn preg_replace_callback(\n\t\t\t'~\\\\\\\\([\\\\\\\\nrtfve]|[xX][0-9a-fA-F]{1,2}|[0-7]{1,3}|u\\{([0-9a-fA-F]+)\\})~',\n\t\t\tstatic function ($matches) {\n\t\t\t\t$str = $matches[1];\n\n\t\t\t\tif (isset(self::REPLACEMENTS[$str])) {\n\t\t\t\t\treturn self::REPLACEMENTS[$str];\n\t\t\t\t}\n\t\t\t\tif ($str[0] === 'x' || $str[0] === 'X') {\n\t\t\t\t\treturn chr((int) hexdec(substr($str, 1)));\n\t\t\t\t}\n\t\t\t\tif ($str[0] === 'u') {\n\t\t\t\t\tif (!isset($matches[2])) {\n\t\t\t\t\t\tthrow new ShouldNotHappenException();\n\t\t\t\t\t}\n\t\t\t\t\treturn self::codePointToUtf8((int) hexdec($matches[2]));\n\t\t\t\t}\n\n\t\t\t\treturn chr((int) octdec($str));\n\t\t\t},\n\t\t\t$str,\n\t\t);\n\t}\n\n\t/**\n\t * Implementation based on https://github.com/nikic/PHP-Parser/blob/b0edd4c41111042d43bb45c6c657b2e0db367d9e/lib/PhpParser/Node/Scalar/String_.php#L132-L154\n\t */\n\tprivate static function codePointToUtf8(int $num): string\n\t{\n\t\tif ($num <= 0x7F) {\n\t\t\treturn chr($num);\n\t\t}\n\t\tif ($num <= 0x7FF) {\n\t\t\treturn chr(($num >> 6) + 0xC0)\n\t\t\t\t. chr(($num & 0x3F) + 0x80);\n\t\t}\n\t\tif ($num <= 0xFFFF) {\n\t\t\treturn chr(($num >> 12) + 0xE0)\n\t\t\t\t. chr((($num >> 6) & 0x3F) + 0x80)\n\t\t\t\t. chr(($num & 0x3F) + 0x80);\n\t\t}\n\t\tif ($num <= 0x1FFFFF) {\n\t\t\treturn chr(($num >> 18) + 0xF0)\n\t\t\t\t. chr((($num >> 12) & 0x3F) + 0x80)\n\t\t\t\t. chr((($num >> 6) & 0x3F) + 0x80)\n\t\t\t\t. chr(($num & 0x3F) + 0x80);\n\t\t}\n\n\t\t// Invalid UTF-8 codepoint escape sequence: Codepoint too large\n\t\treturn \"\\xef\\xbf\\xbd\";\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/TokenIterator.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse LogicException;\nuse PHPStan\\PhpDocParser\\Ast\\Comment;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse function array_pop;\nuse function assert;\nuse function count;\nuse function in_array;\nuse function strlen;\nuse function substr;\n\nclass TokenIterator\n{\n\n\t/** @var list<array{string, int, int}> */\n\tprivate array $tokens;\n\n\tprivate int $index;\n\n\t/** @var list<Comment> */\n\tprivate array $comments = [];\n\n\t/** @var list<array{int, list<Comment>}> */\n\tprivate array $savePoints = [];\n\n\t/** @var list<int> */\n\tprivate array $skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];\n\n\tprivate ?string $newline = null;\n\n\t/**\n\t * @param list<array{string, int, int}> $tokens\n\t */\n\tpublic function __construct(array $tokens, int $index = 0)\n\t{\n\t\t$this->tokens = $tokens;\n\t\t$this->index = $index;\n\n\t\t$this->skipIrrelevantTokens();\n\t}\n\n\t/**\n\t * @return list<array{string, int, int}>\n\t */\n\tpublic function getTokens(): array\n\t{\n\t\treturn $this->tokens;\n\t}\n\n\tpublic function getContentBetween(int $startPos, int $endPos): string\n\t{\n\t\tif ($startPos < 0 || $endPos > count($this->tokens)) {\n\t\t\tthrow new LogicException();\n\t\t}\n\n\t\t$content = '';\n\t\tfor ($i = $startPos; $i < $endPos; $i++) {\n\t\t\t$content .= $this->tokens[$i][Lexer::VALUE_OFFSET];\n\t\t}\n\n\t\treturn $content;\n\t}\n\n\tpublic function getTokenCount(): int\n\t{\n\t\treturn count($this->tokens);\n\t}\n\n\tpublic function currentTokenValue(): string\n\t{\n\t\treturn $this->tokens[$this->index][Lexer::VALUE_OFFSET];\n\t}\n\n\tpublic function currentTokenType(): int\n\t{\n\t\treturn $this->tokens[$this->index][Lexer::TYPE_OFFSET];\n\t}\n\n\tpublic function currentTokenOffset(): int\n\t{\n\t\t$offset = 0;\n\t\tfor ($i = 0; $i < $this->index; $i++) {\n\t\t\t$offset += strlen($this->tokens[$i][Lexer::VALUE_OFFSET]);\n\t\t}\n\n\t\treturn $offset;\n\t}\n\n\tpublic function currentTokenLine(): int\n\t{\n\t\treturn $this->tokens[$this->index][Lexer::LINE_OFFSET];\n\t}\n\n\tpublic function currentTokenIndex(): int\n\t{\n\t\treturn $this->index;\n\t}\n\n\tpublic function endIndexOfLastRelevantToken(): int\n\t{\n\t\t$endIndex = $this->currentTokenIndex();\n\t\t$endIndex--;\n\t\twhile (in_array($this->tokens[$endIndex][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {\n\t\t\tif (!isset($this->tokens[$endIndex - 1])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t$endIndex--;\n\t\t}\n\n\t\treturn $endIndex;\n\t}\n\n\tpublic function isCurrentTokenValue(string $tokenValue): bool\n\t{\n\t\treturn $this->tokens[$this->index][Lexer::VALUE_OFFSET] === $tokenValue;\n\t}\n\n\tpublic function isCurrentTokenType(int ...$tokenType): bool\n\t{\n\t\treturn in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true);\n\t}\n\n\tpublic function isPrecededByHorizontalWhitespace(): bool\n\t{\n\t\treturn ($this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] ?? -1) === Lexer::TOKEN_HORIZONTAL_WS;\n\t}\n\n\t/**\n\t * @throws ParserException\n\t */\n\tpublic function consumeTokenType(int $tokenType): void\n\t{\n\t\tif ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {\n\t\t\t$this->throwError($tokenType);\n\t\t}\n\n\t\tif ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {\n\t\t\tif ($this->newline === null) {\n\t\t\t\t$this->detectNewline();\n\t\t\t}\n\t\t}\n\n\t\t$this->next();\n\t}\n\n\t/**\n\t * @throws ParserException\n\t */\n\tpublic function consumeTokenValue(int $tokenType, string $tokenValue): void\n\t{\n\t\tif ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType || $this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {\n\t\t\t$this->throwError($tokenType, $tokenValue);\n\t\t}\n\n\t\t$this->next();\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function tryConsumeTokenValue(string $tokenValue): bool\n\t{\n\t\tif ($this->tokens[$this->index][Lexer::VALUE_OFFSET] !== $tokenValue) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$this->next();\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @return list<Comment>\n\t */\n\tpublic function flushComments(): array\n\t{\n\t\t$res = $this->comments;\n\t\t$this->comments = [];\n\t\treturn $res;\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function tryConsumeTokenType(int $tokenType): bool\n\t{\n\t\tif ($this->tokens[$this->index][Lexer::TYPE_OFFSET] !== $tokenType) {\n\t\t\treturn false;\n\t\t}\n\n\t\tif ($tokenType === Lexer::TOKEN_PHPDOC_EOL) {\n\t\t\tif ($this->newline === null) {\n\t\t\t\t$this->detectNewline();\n\t\t\t}\n\t\t}\n\n\t\t$this->next();\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * @deprecated Use skipNewLineTokensAndConsumeComments instead (when parsing a type)\n\t */\n\tpublic function skipNewLineTokens(): void\n\t{\n\t\tif (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdo {\n\t\t\t$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);\n\t\t} while ($foundNewLine === true);\n\t}\n\n\tpublic function skipNewLineTokensAndConsumeComments(): void\n\t{\n\t\tif ($this->currentTokenType() === Lexer::TOKEN_COMMENT) {\n\t\t\t$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());\n\t\t\t$this->next();\n\t\t}\n\n\t\tif (!$this->isCurrentTokenType(Lexer::TOKEN_PHPDOC_EOL)) {\n\t\t\treturn;\n\t\t}\n\n\t\tdo {\n\t\t\t$foundNewLine = $this->tryConsumeTokenType(Lexer::TOKEN_PHPDOC_EOL);\n\t\t\tif ($this->currentTokenType() !== Lexer::TOKEN_COMMENT) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$this->comments[] = new Comment($this->currentTokenValue(), $this->currentTokenLine(), $this->currentTokenIndex());\n\t\t\t$this->next();\n\t\t} while ($foundNewLine === true);\n\t}\n\n\tprivate function detectNewline(): void\n\t{\n\t\t$value = $this->currentTokenValue();\n\t\tif (substr($value, 0, 2) === \"\\r\\n\") {\n\t\t\t$this->newline = \"\\r\\n\";\n\t\t} elseif (substr($value, 0, 1) === \"\\n\") {\n\t\t\t$this->newline = \"\\n\";\n\t\t}\n\t}\n\n\tpublic function getSkippedHorizontalWhiteSpaceIfAny(): string\n\t{\n\t\tif ($this->index > 0 && $this->tokens[$this->index - 1][Lexer::TYPE_OFFSET] === Lexer::TOKEN_HORIZONTAL_WS) {\n\t\t\treturn $this->tokens[$this->index - 1][Lexer::VALUE_OFFSET];\n\t\t}\n\n\t\treturn '';\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function joinUntil(int ...$tokenType): string\n\t{\n\t\t$s = '';\n\t\twhile (!in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $tokenType, true)) {\n\t\t\t$s .= $this->tokens[$this->index++][Lexer::VALUE_OFFSET];\n\t\t}\n\t\treturn $s;\n\t}\n\n\tpublic function next(): void\n\t{\n\t\t$this->index++;\n\t\t$this->skipIrrelevantTokens();\n\t}\n\n\tprivate function skipIrrelevantTokens(): void\n\t{\n\t\tif (!isset($this->tokens[$this->index])) {\n\t\t\treturn;\n\t\t}\n\n\t\twhile (in_array($this->tokens[$this->index][Lexer::TYPE_OFFSET], $this->skippedTokenTypes, true)) {\n\t\t\tif (!isset($this->tokens[$this->index + 1])) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t$this->index++;\n\t\t}\n\t}\n\n\tpublic function addEndOfLineToSkippedTokens(): void\n\t{\n\t\t$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS, Lexer::TOKEN_PHPDOC_EOL];\n\t}\n\n\tpublic function removeEndOfLineFromSkippedTokens(): void\n\t{\n\t\t$this->skippedTokenTypes = [Lexer::TOKEN_HORIZONTAL_WS];\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function forwardToTheEnd(): void\n\t{\n\t\t$lastToken = count($this->tokens) - 1;\n\t\t$this->index = $lastToken;\n\t}\n\n\tpublic function pushSavePoint(): void\n\t{\n\t\t$this->savePoints[] = [$this->index, $this->comments];\n\t}\n\n\tpublic function dropSavePoint(): void\n\t{\n\t\tarray_pop($this->savePoints);\n\t}\n\n\tpublic function rollback(): void\n\t{\n\t\t$savepoint = array_pop($this->savePoints);\n\t\tassert($savepoint !== null);\n\t\t[$this->index, $this->comments] = $savepoint;\n\t}\n\n\t/**\n\t * @throws ParserException\n\t */\n\tprivate function throwError(int $expectedTokenType, ?string $expectedTokenValue = null): void\n\t{\n\t\tthrow new ParserException(\n\t\t\t$this->currentTokenValue(),\n\t\t\t$this->currentTokenType(),\n\t\t\t$this->currentTokenOffset(),\n\t\t\t$expectedTokenType,\n\t\t\t$expectedTokenValue,\n\t\t\t$this->currentTokenLine(),\n\t\t);\n\t}\n\n\t/**\n\t * Check whether the position is directly preceded by a certain token type.\n\t *\n\t * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped\n\t */\n\tpublic function hasTokenImmediatelyBefore(int $pos, int $expectedTokenType): bool\n\t{\n\t\t$tokens = $this->tokens;\n\t\t$pos--;\n\t\tfor (; $pos >= 0; $pos--) {\n\t\t\t$token = $tokens[$pos];\n\t\t\t$type = $token[Lexer::TYPE_OFFSET];\n\t\t\tif ($type === $expectedTokenType) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (!in_array($type, [\n\t\t\t\tLexer::TOKEN_HORIZONTAL_WS,\n\t\t\t\tLexer::TOKEN_PHPDOC_EOL,\n\t\t\t], true)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\t/**\n\t * Check whether the position is directly followed by a certain token type.\n\t *\n\t * During this check TOKEN_HORIZONTAL_WS and TOKEN_PHPDOC_EOL are skipped\n\t */\n\tpublic function hasTokenImmediatelyAfter(int $pos, int $expectedTokenType): bool\n\t{\n\t\t$tokens = $this->tokens;\n\t\t$pos++;\n\t\tfor ($c = count($tokens); $pos < $c; $pos++) {\n\t\t\t$token = $tokens[$pos];\n\t\t\t$type = $token[Lexer::TYPE_OFFSET];\n\t\t\tif ($type === $expectedTokenType) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif (!in_array($type, [\n\t\t\t\tLexer::TOKEN_HORIZONTAL_WS,\n\t\t\t\tLexer::TOKEN_PHPDOC_EOL,\n\t\t\t], true)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n\n\tpublic function getDetectedNewline(): ?string\n\t{\n\t\treturn $this->newline;\n\t}\n\n\t/**\n\t * Whether the given position is immediately surrounded by parenthesis.\n\t */\n\tpublic function hasParentheses(int $startPos, int $endPos): bool\n\t{\n\t\treturn $this->hasTokenImmediatelyBefore($startPos, Lexer::TOKEN_OPEN_PARENTHESES)\n\t\t\t&& $this->hasTokenImmediatelyAfter($endPos, Lexer::TOKEN_CLOSE_PARENTHESES);\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Parser/TypeParser.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Parser;\n\nuse LogicException;\nuse PHPStan\\PhpDocParser\\Ast;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\ParserConfig;\nuse function in_array;\nuse function str_replace;\nuse function strlen;\nuse function strpos;\nuse function substr_compare;\n\nclass TypeParser\n{\n\n\tprivate ParserConfig $config;\n\n\tprivate ConstExprParser $constExprParser;\n\n\tpublic function __construct(\n\t\tParserConfig $config,\n\t\tConstExprParser $constExprParser\n\t)\n\t{\n\t\t$this->config = $config;\n\t\t$this->constExprParser = $constExprParser;\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function parse(TokenIterator $tokens): Ast\\Type\\TypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {\n\t\t\t$type = $this->parseNullable($tokens);\n\n\t\t} else {\n\t\t\t$type = $this->parseAtomic($tokens);\n\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\ttry {\n\t\t\t\t$enrichedType = $this->enrichTypeOnUnionOrIntersection($tokens, $type);\n\n\t\t\t} catch (ParserException $parserException) {\n\t\t\t\t$enrichedType = null;\n\t\t\t}\n\n\t\t\tif ($enrichedType !== null) {\n\t\t\t\t$type = $enrichedType;\n\t\t\t\t$tokens->dropSavePoint();\n\n\t\t\t} else {\n\t\t\t\t$tokens->rollback();\n\t\t\t\t$type = $this->enrichTypeOnUnionOrIntersection($tokens, $type) ?? $type;\n\t\t\t}\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function enrichTypeOnUnionOrIntersection(TokenIterator $tokens, Ast\\Type\\TypeNode $type): ?Ast\\Type\\TypeNode\n\t{\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {\n\t\t\treturn $this->parseUnion($tokens, $type);\n\n\t\t}\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {\n\t\t\treturn $this->parseIntersection($tokens, $type);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\t/**\n\t * @internal\n\t * @template T of Ast\\Node\n\t * @param T $type\n\t * @return T\n\t */\n\tpublic function enrichWithAttributes(TokenIterator $tokens, Ast\\Node $type, int $startLine, int $startIndex): Ast\\Node\n\t{\n\t\tif ($this->config->useLinesAttributes) {\n\t\t\t$type->setAttribute(Ast\\Attribute::START_LINE, $startLine);\n\t\t\t$type->setAttribute(Ast\\Attribute::END_LINE, $tokens->currentTokenLine());\n\t\t}\n\n\t\t$comments = $tokens->flushComments();\n\t\tif ($this->config->useCommentsAttributes) {\n\t\t\t$type->setAttribute(Ast\\Attribute::COMMENTS, $comments);\n\t\t}\n\n\t\tif ($this->config->useIndexAttributes) {\n\t\t\t$type->setAttribute(Ast\\Attribute::START_INDEX, $startIndex);\n\t\t\t$type->setAttribute(Ast\\Attribute::END_INDEX, $tokens->endIndexOfLastRelevantToken());\n\t\t}\n\n\t\treturn $type;\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function subParse(TokenIterator $tokens): Ast\\Type\\TypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {\n\t\t\t$type = $this->parseNullable($tokens);\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {\n\t\t\t$type = $this->parseConditionalForParameter($tokens, $tokens->currentTokenValue());\n\n\t\t} else {\n\t\t\t$type = $this->parseAtomic($tokens);\n\n\t\t\tif ($tokens->isCurrentTokenValue('is')) {\n\t\t\t\t$type = $this->parseConditional($tokens, $type);\n\t\t\t} else {\n\t\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {\n\t\t\t\t\t$type = $this->subParseUnion($tokens, $type);\n\n\t\t\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {\n\t\t\t\t\t$type = $this->subParseIntersection($tokens, $type);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseAtomic(TokenIterator $tokens): Ast\\Type\\TypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t$type = $this->subParse($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t}\n\n\t\t\treturn $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t\t}\n\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {\n\t\t\t$type = $this->enrichWithAttributes($tokens, new Ast\\Type\\ThisTypeNode(), $startLine, $startIndex);\n\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t}\n\n\t\t\treturn $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t\t}\n\n\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t$tokens->pushSavePoint(); // because of ConstFetchNode\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t$type = $this->enrichWithAttributes($tokens, new Ast\\Type\\IdentifierTypeNode($currentTokenValue), $startLine, $startIndex);\n\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t$tokens->dropSavePoint(); // because of ConstFetchNode\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {\n\t\t\t\t\t$tokens->pushSavePoint();\n\n\t\t\t\t\t$isHtml = $this->isHtml($tokens);\n\t\t\t\t\t$tokens->rollback();\n\t\t\t\t\tif ($isHtml) {\n\t\t\t\t\t\treturn $type;\n\t\t\t\t\t}\n\n\t\t\t\t\t$origType = $type;\n\t\t\t\t\t$type = $this->tryParseCallable($tokens, $type, true);\n\t\t\t\t\tif ($type === $origType) {\n\t\t\t\t\t\t$type = $this->parseGeneric($tokens, $type);\n\n\t\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t\t\t$type = $this->tryParseCallable($tokens, $type, false);\n\n\t\t\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\n\t\t\t\t} elseif (in_array($type->name, [\n\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_ARRAY,\n\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_LIST,\n\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,\n\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_NON_EMPTY_LIST,\n\t\t\t\t\t'object',\n\t\t\t\t], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {\n\t\t\t\t\tif ($type->name === 'object') {\n\t\t\t\t\t\t$type = $this->parseObjectShape($tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$type = $this->parseArrayShape($tokens, $type, $type->name);\n\t\t\t\t\t}\n\n\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess(\n\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t$this->enrichWithAttributes($tokens, $type, $startLine, $startIndex),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t\t\t} else {\n\t\t\t\t$tokens->rollback(); // because of ConstFetchNode\n\t\t\t}\n\t\t} else {\n\t\t\t$tokens->dropSavePoint(); // because of ConstFetchNode\n\t\t}\n\n\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t$currentTokenType = $tokens->currentTokenType();\n\t\t$currentTokenOffset = $tokens->currentTokenOffset();\n\t\t$currentTokenLine = $tokens->currentTokenLine();\n\n\t\ttry {\n\t\t\t$constExpr = $this->constExprParser->parse($tokens);\n\t\t\tif ($constExpr instanceof Ast\\ConstExpr\\ConstExprArrayNode) {\n\t\t\t\tthrow new ParserException(\n\t\t\t\t\t$currentTokenValue,\n\t\t\t\t\t$currentTokenType,\n\t\t\t\t\t$currentTokenOffset,\n\t\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\t\tnull,\n\t\t\t\t\t$currentTokenLine,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t$type = $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\Type\\ConstTypeNode($constExpr),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t}\n\n\t\t\treturn $type;\n\t\t} catch (LogicException $e) {\n\t\t\tthrow new ParserException(\n\t\t\t\t$currentTokenValue,\n\t\t\t\t$currentTokenType,\n\t\t\t\t$currentTokenOffset,\n\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\tnull,\n\t\t\t\t$currentTokenLine,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseUnion(TokenIterator $tokens, Ast\\Type\\TypeNode $type): Ast\\Type\\TypeNode\n\t{\n\t\t$types = [$type];\n\n\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {\n\t\t\t$types[] = $this->parseAtomic($tokens);\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_UNION)) {\n\t\t\t\t$tokens->rollback();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tokens->dropSavePoint();\n\t\t}\n\n\t\treturn new Ast\\Type\\UnionTypeNode($types);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function subParseUnion(TokenIterator $tokens, Ast\\Type\\TypeNode $type): Ast\\Type\\TypeNode\n\t{\n\t\t$types = [$type];\n\n\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_UNION)) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t$types[] = $this->parseAtomic($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t}\n\n\t\treturn new Ast\\Type\\UnionTypeNode($types);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseIntersection(TokenIterator $tokens, Ast\\Type\\TypeNode $type): Ast\\Type\\TypeNode\n\t{\n\t\t$types = [$type];\n\n\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {\n\t\t\t$types[] = $this->parseAtomic($tokens);\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_INTERSECTION)) {\n\t\t\t\t$tokens->rollback();\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$tokens->dropSavePoint();\n\t\t}\n\n\t\treturn new Ast\\Type\\IntersectionTypeNode($types);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function subParseIntersection(TokenIterator $tokens, Ast\\Type\\TypeNode $type): Ast\\Type\\TypeNode\n\t{\n\t\t$types = [$type];\n\n\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_INTERSECTION)) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t$types[] = $this->parseAtomic($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t}\n\n\t\treturn new Ast\\Type\\IntersectionTypeNode($types);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseConditional(TokenIterator $tokens, Ast\\Type\\TypeNode $subjectType): Ast\\Type\\TypeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t$negated = false;\n\t\tif ($tokens->isCurrentTokenValue('not')) {\n\t\t\t$negated = true;\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t}\n\n\t\t$targetType = $this->parse($tokens);\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$ifType = $this->parse($tokens);\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_COLON);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$elseType = $this->subParse($tokens);\n\n\t\treturn new Ast\\Type\\ConditionalTypeNode($subjectType, $targetType, $ifType, $elseType, $negated);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseConditionalForParameter(TokenIterator $tokens, string $parameterName): Ast\\Type\\TypeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);\n\t\t$tokens->consumeTokenValue(Lexer::TOKEN_IDENTIFIER, 'is');\n\n\t\t$negated = false;\n\t\tif ($tokens->isCurrentTokenValue('not')) {\n\t\t\t$negated = true;\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t}\n\n\t\t$targetType = $this->parse($tokens);\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$ifType = $this->parse($tokens);\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_COLON);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$elseType = $this->subParse($tokens);\n\n\t\treturn new Ast\\Type\\ConditionalTypeForParameterNode($parameterName, $targetType, $ifType, $elseType, $negated);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseNullable(TokenIterator $tokens): Ast\\Type\\TypeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_NULLABLE);\n\n\t\t$type = $this->parseAtomic($tokens);\n\n\t\treturn new Ast\\Type\\NullableTypeNode($type);\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function isHtml(TokenIterator $tokens): bool\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);\n\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$htmlTagName = $tokens->currentTokenValue();\n\n\t\t$tokens->next();\n\n\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {\n\t\t\treturn false;\n\t\t}\n\n\t\t$endTag = '</' . $htmlTagName . '>';\n\t\t$endTagSearchOffset = - strlen($endTag);\n\n\t\twhile (!$tokens->isCurrentTokenType(Lexer::TOKEN_END)) {\n\t\t\tif (\n\t\t\t\t(\n\t\t\t\t\t$tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)\n\t\t\t\t\t&& strpos($tokens->currentTokenValue(), '/' . $htmlTagName . '>') !== false\n\t\t\t\t)\n\t\t\t\t|| substr_compare($tokens->currentTokenValue(), $endTag, $endTagSearchOffset) === 0\n\t\t\t) {\n\t\t\t\treturn true;\n\t\t\t}\n\n\t\t\t$tokens->next();\n\t\t}\n\n\t\treturn false;\n\t}\n\n\t/** @phpstan-impure */\n\tpublic function parseGeneric(TokenIterator $tokens, Ast\\Type\\IdentifierTypeNode $baseType): Ast\\Type\\GenericTypeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$startLine = $baseType->getAttribute(Ast\\Attribute::START_LINE);\n\t\t$startIndex = $baseType->getAttribute(Ast\\Attribute::START_INDEX);\n\t\t$genericTypes = [];\n\t\t$variances = [];\n\n\t\t$isFirst = true;\n\t\twhile (\n\t\t\t$isFirst\n\t\t\t|| $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)\n\t\t) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\t// trailing comma case\n\t\t\tif (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t$isFirst = false;\n\n\t\t\t[$genericTypes[], $variances[]] = $this->parseGenericTypeArgument($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t}\n\n\t\t$type = new Ast\\Type\\GenericTypeNode($baseType, $genericTypes, $variances);\n\t\tif ($startLine !== null && $startIndex !== null) {\n\t\t\t$type = $this->enrichWithAttributes($tokens, $type, $startLine, $startIndex);\n\t\t} else {\n\t\t\t// The comments read between the arguments have to be given away\n\t\t\t// even where the node is not placed, or they would still be waiting\n\t\t\t// for a node once the whole PHPDoc has been read\n\t\t\t$tokens->flushComments();\n\t\t}\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);\n\n\t\treturn $type;\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t * @return array{Ast\\Type\\TypeNode, Ast\\Type\\GenericTypeNode::VARIANCE_*}\n\t */\n\tpublic function parseGenericTypeArgument(TokenIterator $tokens): array\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_WILDCARD)) {\n\t\t\treturn [\n\t\t\t\t$this->enrichWithAttributes($tokens, new Ast\\Type\\IdentifierTypeNode('mixed'), $startLine, $startIndex),\n\t\t\t\tAst\\Type\\GenericTypeNode::VARIANCE_BIVARIANT,\n\t\t\t];\n\t\t}\n\n\t\tif ($tokens->tryConsumeTokenValue('contravariant')) {\n\t\t\t$variance = Ast\\Type\\GenericTypeNode::VARIANCE_CONTRAVARIANT;\n\t\t} elseif ($tokens->tryConsumeTokenValue('covariant')) {\n\t\t\t$variance = Ast\\Type\\GenericTypeNode::VARIANCE_COVARIANT;\n\t\t} else {\n\t\t\t$variance = Ast\\Type\\GenericTypeNode::VARIANCE_INVARIANT;\n\t\t}\n\n\t\t$type = $this->parse($tokens);\n\t\treturn [$type, $variance];\n\t}\n\n\t/**\n\t * @throws ParserException\n\t * @param ?callable(TokenIterator): string $parseDescription\n\t */\n\tpublic function parseTemplateTagValue(\n\t\tTokenIterator $tokens,\n\t\t?callable $parseDescription = null\n\t): TemplateTagValueNode\n\t{\n\t\t$name = $tokens->currentTokenValue();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t$upperBound = $lowerBound = null;\n\n\t\tif ($tokens->tryConsumeTokenValue('of') || $tokens->tryConsumeTokenValue('as')) {\n\t\t\t$upperBound = $this->parse($tokens);\n\t\t}\n\n\t\tif ($tokens->tryConsumeTokenValue('super')) {\n\t\t\t$lowerBound = $this->parse($tokens);\n\t\t}\n\n\t\tif ($tokens->tryConsumeTokenValue('=')) {\n\t\t\t$default = $this->parse($tokens);\n\t\t} else {\n\t\t\t$default = null;\n\t\t}\n\n\t\tif ($parseDescription !== null) {\n\t\t\t$description = $parseDescription($tokens);\n\t\t} else {\n\t\t\t$description = '';\n\t\t}\n\n\t\tif ($name === '') {\n\t\t\tthrow new LogicException('Template tag name cannot be empty.');\n\t\t}\n\n\t\treturn new Ast\\PhpDoc\\TemplateTagValueNode($name, $upperBound, $description, $default, $lowerBound);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseCallable(TokenIterator $tokens, Ast\\Type\\IdentifierTypeNode $identifier, bool $hasTemplate): Ast\\Type\\TypeNode\n\t{\n\t\t$templates = $hasTemplate\n\t\t\t? $this->parseCallableTemplates($tokens)\n\t\t\t: [];\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$parameters = [];\n\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {\n\t\t\t$parameters[] = $this->parseCallableParameter($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\twhile ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {\n\t\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_PARENTHESES)) {\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\t$parameters[] = $this->parseCallableParameter($tokens);\n\t\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t}\n\t\t}\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_COLON);\n\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t$returnType = $this->enrichWithAttributes($tokens, $this->parseCallableReturnType($tokens), $startLine, $startIndex);\n\n\t\treturn new Ast\\Type\\CallableTypeNode($identifier, $parameters, $returnType, $templates);\n\t}\n\n\t/**\n\t * @return Ast\\PhpDoc\\TemplateTagValueNode[]\n\t *\n\t * @phpstan-impure\n\t */\n\tprivate function parseCallableTemplates(TokenIterator $tokens): array\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);\n\n\t\t$templates = [];\n\n\t\t$isFirst = true;\n\t\twhile ($isFirst || $tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\t// trailing comma case\n\t\t\tif (!$isFirst && $tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET)) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t$isFirst = false;\n\n\t\t\t$templates[] = $this->parseCallableTemplateArgument($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t}\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);\n\n\t\treturn $templates;\n\t}\n\n\tprivate function parseCallableTemplateArgument(TokenIterator $tokens): Ast\\PhpDoc\\TemplateTagValueNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\t$this->parseTemplateTagValue($tokens),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseCallableParameter(TokenIterator $tokens): Ast\\Type\\CallableTypeParameterNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t$type = $this->parse($tokens);\n\t\t$isReference = $tokens->tryConsumeTokenType(Lexer::TOKEN_REFERENCE);\n\t\t$isVariadic = $tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC);\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_VARIABLE)) {\n\t\t\t$parameterName = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_VARIABLE);\n\n\t\t} else {\n\t\t\t$parameterName = '';\n\t\t}\n\n\t\t$isOptional = $tokens->tryConsumeTokenType(Lexer::TOKEN_EQUAL);\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\Type\\CallableTypeParameterNode($type, $isReference, $isVariadic, $parameterName, $isOptional),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseCallableReturnType(TokenIterator $tokens): Ast\\Type\\TypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_NULLABLE)) {\n\t\t\treturn $this->parseNullable($tokens);\n\n\t\t} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_OPEN_PARENTHESES)) {\n\t\t\t$type = $this->subParse($tokens);\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_PARENTHESES);\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t}\n\n\t\t\treturn $type;\n\t\t} elseif ($tokens->tryConsumeTokenType(Lexer::TOKEN_THIS_VARIABLE)) {\n\t\t\t$type = new Ast\\Type\\ThisTypeNode();\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(\n\t\t\t\t\t$tokens,\n\t\t\t\t\t$type,\n\t\t\t\t\t$startLine,\n\t\t\t\t\t$startIndex,\n\t\t\t\t));\n\t\t\t}\n\n\t\t\treturn $type;\n\t\t} else {\n\t\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t\t$tokens->pushSavePoint(); // because of ConstFetchNode\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_IDENTIFIER)) {\n\t\t\t\t$type = new Ast\\Type\\IdentifierTypeNode($currentTokenValue);\n\n\t\t\t\tif (!$tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {\n\t\t\t\t\t\t$type = $this->parseGeneric(\n\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t$this->enrichWithAttributes(\n\t\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(\n\t\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t\t));\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(\n\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t));\n\n\t\t\t\t\t} elseif (in_array($type->name, [\n\t\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_ARRAY,\n\t\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_LIST,\n\t\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_NON_EMPTY_ARRAY,\n\t\t\t\t\t\tAst\\Type\\ArrayShapeNode::KIND_NON_EMPTY_LIST,\n\t\t\t\t\t\t'object',\n\t\t\t\t\t], true) && $tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET) && !$tokens->isPrecededByHorizontalWhitespace()) {\n\t\t\t\t\t\tif ($type->name === 'object') {\n\t\t\t\t\t\t\t$type = $this->parseObjectShape($tokens);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$type = $this->parseArrayShape($tokens, $this->enrichWithAttributes(\n\t\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t\t), $type->name);\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $this->enrichWithAttributes(\n\t\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t\t));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\treturn $type;\n\t\t\t\t} else {\n\t\t\t\t\t$tokens->rollback(); // because of ConstFetchNode\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t$tokens->dropSavePoint(); // because of ConstFetchNode\n\t\t\t}\n\t\t}\n\n\t\t$currentTokenValue = $tokens->currentTokenValue();\n\t\t$currentTokenType = $tokens->currentTokenType();\n\t\t$currentTokenOffset = $tokens->currentTokenOffset();\n\t\t$currentTokenLine = $tokens->currentTokenLine();\n\n\t\ttry {\n\t\t\t$constExpr = $this->constExprParser->parse($tokens);\n\t\t\tif ($constExpr instanceof Ast\\ConstExpr\\ConstExprArrayNode) {\n\t\t\t\tthrow new ParserException(\n\t\t\t\t\t$currentTokenValue,\n\t\t\t\t\t$currentTokenType,\n\t\t\t\t\t$currentTokenOffset,\n\t\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\t\tnull,\n\t\t\t\t\t$currentTokenLine,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t$type = $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\Type\\ConstTypeNode($constExpr),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$type = $this->tryParseArrayOrOffsetAccess($tokens, $type);\n\t\t\t}\n\n\t\t\treturn $type;\n\t\t} catch (LogicException $e) {\n\t\t\tthrow new ParserException(\n\t\t\t\t$currentTokenValue,\n\t\t\t\t$currentTokenType,\n\t\t\t\t$currentTokenOffset,\n\t\t\t\tLexer::TOKEN_IDENTIFIER,\n\t\t\t\tnull,\n\t\t\t\t$currentTokenLine,\n\t\t\t);\n\t\t}\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function tryParseCallable(TokenIterator $tokens, Ast\\Type\\IdentifierTypeNode $identifier, bool $hasTemplate): Ast\\Type\\TypeNode\n\t{\n\t\ttry {\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$type = $this->parseCallable($tokens, $identifier, $hasTemplate);\n\t\t\t$tokens->dropSavePoint();\n\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\t\t\t$type = $identifier;\n\t\t}\n\n\t\treturn $type;\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function tryParseArrayOrOffsetAccess(TokenIterator $tokens, Ast\\Type\\TypeNode $type): Ast\\Type\\TypeNode\n\t{\n\t\t$startLine = $type->getAttribute(Ast\\Attribute::START_LINE);\n\t\t$startIndex = $type->getAttribute(Ast\\Attribute::START_INDEX);\n\t\ttry {\n\t\t\twhile ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET)) {\n\t\t\t\t$tokens->pushSavePoint();\n\n\t\t\t\t$canBeOffsetAccessType = !$tokens->isPrecededByHorizontalWhitespace();\n\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_SQUARE_BRACKET);\n\n\t\t\t\tif ($canBeOffsetAccessType && !$tokens->isCurrentTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET)) {\n\t\t\t\t\t$offset = $this->parse($tokens);\n\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);\n\t\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\t\t$type = new Ast\\Type\\OffsetAccessTypeNode($type, $offset);\n\n\t\t\t\t\tif ($startLine !== null && $startIndex !== null) {\n\t\t\t\t\t\t$type = $this->enrichWithAttributes(\n\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_SQUARE_BRACKET);\n\t\t\t\t\t$tokens->dropSavePoint();\n\t\t\t\t\t$type = new Ast\\Type\\ArrayTypeNode($type);\n\n\t\t\t\t\tif ($startLine !== null && $startIndex !== null) {\n\t\t\t\t\t\t$type = $this->enrichWithAttributes(\n\t\t\t\t\t\t\t$tokens,\n\t\t\t\t\t\t\t$type,\n\t\t\t\t\t\t\t$startLine,\n\t\t\t\t\t\t\t$startIndex,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\t\t}\n\n\t\treturn $type;\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t * @param Ast\\Type\\ArrayShapeNode::KIND_* $kind\n\t */\n\tprivate function parseArrayShape(TokenIterator $tokens, Ast\\Type\\TypeNode $type, string $kind): Ast\\Type\\ArrayShapeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);\n\n\t\t$items = [];\n\t\t$sealed = true;\n\t\t$unsealedType = null;\n\n\t\t$done = false;\n\n\t\tdo {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {\n\t\t\t\treturn Ast\\Type\\ArrayShapeNode::createSealed($items, $kind);\n\t\t\t}\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_VARIADIC)) {\n\t\t\t\t$sealed = false;\n\n\t\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET)) {\n\t\t\t\t\tif ($kind === Ast\\Type\\ArrayShapeNode::KIND_ARRAY) {\n\t\t\t\t\t\t$unsealedType = $this->parseArrayShapeUnsealedType($tokens);\n\t\t\t\t\t} else {\n\t\t\t\t\t\t$unsealedType = $this->parseListShapeUnsealedType($tokens);\n\t\t\t\t\t}\n\t\t\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\t\t}\n\n\t\t\t\t$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\t$items[] = $this->parseArrayShapeItem($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t\tif (!$tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {\n\t\t\t\t$done = true;\n\t\t\t}\n\t\t\tif ($tokens->currentTokenType() !== Lexer::TOKEN_COMMENT) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$tokens->next();\n\n\t\t} while (!$done);\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);\n\n\t\tif ($sealed) {\n\t\t\treturn Ast\\Type\\ArrayShapeNode::createSealed($items, $kind);\n\t\t}\n\n\t\treturn Ast\\Type\\ArrayShapeNode::createUnsealed($items, $unsealedType, $kind);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseArrayShapeItem(TokenIterator $tokens): Ast\\Type\\ArrayShapeItemNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t// parse any comments above the item\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\ttry {\n\t\t\t$tokens->pushSavePoint();\n\t\t\t$key = $this->parseArrayShapeKey($tokens);\n\t\t\t$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_COLON);\n\t\t\t$value = $this->parse($tokens);\n\n\t\t\t$tokens->dropSavePoint();\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\Type\\ArrayShapeItemNode($key, $optional, $value),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t} catch (ParserException $e) {\n\t\t\t$tokens->rollback();\n\t\t\t$value = $this->parse($tokens);\n\n\t\t\treturn $this->enrichWithAttributes(\n\t\t\t\t$tokens,\n\t\t\t\tnew Ast\\Type\\ArrayShapeItemNode(null, false, $value),\n\t\t\t\t$startLine,\n\t\t\t\t$startIndex,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t * @return Ast\\ConstExpr\\ConstExprIntegerNode|Ast\\ConstExpr\\ConstExprStringNode|Ast\\ConstExpr\\ConstFetchNode|Ast\\Type\\IdentifierTypeNode\n\t */\n\tprivate function parseArrayShapeKey(TokenIterator $tokens)\n\t{\n\t\t$startIndex = $tokens->currentTokenIndex();\n\t\t$startLine = $tokens->currentTokenLine();\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_INTEGER)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprIntegerNode(str_replace('_', '', $tokens->currentTokenValue()));\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\\ConstExpr\\ConstExprStringNode::SINGLE_QUOTED);\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\\ConstExpr\\ConstExprStringNode::DOUBLE_QUOTED);\n\n\t\t\t$tokens->next();\n\n\t\t} else {\n\t\t\t$identifier = $tokens->currentTokenValue();\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_DOUBLE_COLON)) {\n\t\t\t\t$classConstantName = $tokens->currentTokenValue();\n\t\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\n\t\t\t\t$key = new Ast\\ConstExpr\\ConstFetchNode($identifier, $classConstantName);\n\t\t\t} else {\n\t\t\t\t$key = new Ast\\Type\\IdentifierTypeNode($identifier);\n\t\t\t}\n\t\t}\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\t$key,\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t */\n\tprivate function parseArrayShapeUnsealedType(TokenIterator $tokens): Ast\\Type\\ArrayShapeUnsealedTypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$valueType = $this->parse($tokens);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$keyType = null;\n\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA)) {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\t$keyType = $valueType;\n\t\t\t$valueType = $this->parse($tokens);\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t}\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\Type\\ArrayShapeUnsealedTypeNode($valueType, $keyType),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t */\n\tprivate function parseListShapeUnsealedType(TokenIterator $tokens): Ast\\Type\\ArrayShapeUnsealedTypeNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_ANGLE_BRACKET);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$valueType = $this->parse($tokens);\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_ANGLE_BRACKET);\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\Type\\ArrayShapeUnsealedTypeNode($valueType, null),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t */\n\tprivate function parseObjectShape(TokenIterator $tokens): Ast\\Type\\ObjectShapeNode\n\t{\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_OPEN_CURLY_BRACKET);\n\n\t\t$items = [];\n\n\t\tdo {\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t\tif ($tokens->tryConsumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET)) {\n\t\t\t\treturn new Ast\\Type\\ObjectShapeNode($items);\n\t\t\t}\n\n\t\t\t$items[] = $this->parseObjectShapeItem($tokens);\n\n\t\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t} while ($tokens->tryConsumeTokenType(Lexer::TOKEN_COMMA));\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_CLOSE_CURLY_BRACKET);\n\n\t\treturn new Ast\\Type\\ObjectShapeNode($items);\n\t}\n\n\t/** @phpstan-impure */\n\tprivate function parseObjectShapeItem(TokenIterator $tokens): Ast\\Type\\ObjectShapeItemNode\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\t$tokens->skipNewLineTokensAndConsumeComments();\n\n\t\t$key = $this->parseObjectShapeKey($tokens);\n\t\t$optional = $tokens->tryConsumeTokenType(Lexer::TOKEN_NULLABLE);\n\t\t$tokens->consumeTokenType(Lexer::TOKEN_COLON);\n\t\t$value = $this->parse($tokens);\n\n\t\treturn $this->enrichWithAttributes(\n\t\t\t$tokens,\n\t\t\tnew Ast\\Type\\ObjectShapeItemNode($key, $optional, $value),\n\t\t\t$startLine,\n\t\t\t$startIndex,\n\t\t);\n\t}\n\n\t/**\n\t * @phpstan-impure\n\t * @return Ast\\ConstExpr\\ConstExprStringNode|Ast\\Type\\IdentifierTypeNode\n\t */\n\tprivate function parseObjectShapeKey(TokenIterator $tokens)\n\t{\n\t\t$startLine = $tokens->currentTokenLine();\n\t\t$startIndex = $tokens->currentTokenIndex();\n\n\t\tif ($tokens->isCurrentTokenType(Lexer::TOKEN_SINGLE_QUOTED_STRING)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\\ConstExpr\\ConstExprStringNode::SINGLE_QUOTED);\n\t\t\t$tokens->next();\n\n\t\t} elseif ($tokens->isCurrentTokenType(Lexer::TOKEN_DOUBLE_QUOTED_STRING)) {\n\t\t\t$key = new Ast\\ConstExpr\\ConstExprStringNode(StringUnescaper::unescapeString($tokens->currentTokenValue()), Ast\\ConstExpr\\ConstExprStringNode::DOUBLE_QUOTED);\n\t\t\t$tokens->next();\n\n\t\t} else {\n\t\t\t$key = new Ast\\Type\\IdentifierTypeNode($tokens->currentTokenValue());\n\t\t\t$tokens->consumeTokenType(Lexer::TOKEN_IDENTIFIER);\n\t\t}\n\n\t\treturn $this->enrichWithAttributes($tokens, $key, $startLine, $startIndex);\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/ParserConfig.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser;\n\nclass ParserConfig\n{\n\n\tpublic bool $useLinesAttributes;\n\n\tpublic bool $useIndexAttributes;\n\n\tpublic bool $useCommentsAttributes;\n\n\t/**\n\t * @param array{lines?: bool, indexes?: bool, comments?: bool} $usedAttributes\n\t */\n\tpublic function __construct(array $usedAttributes)\n\t{\n\t\t$this->useLinesAttributes = $usedAttributes['lines'] ?? false;\n\t\t$this->useIndexAttributes = $usedAttributes['indexes'] ?? false;\n\t\t$this->useCommentsAttributes = $usedAttributes['comments'] ?? false;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Printer/DiffElem.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Printer;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n *\n * Implements the Myers diff algorithm.\n *\n * @internal\n */\nclass DiffElem\n{\n\n\tpublic const TYPE_KEEP = 0;\n\tpublic const TYPE_REMOVE = 1;\n\tpublic const TYPE_ADD = 2;\n\tpublic const TYPE_REPLACE = 3;\n\n\t/** @var self::TYPE_* */\n\tpublic $type;\n\n\t/** @var mixed Is null for add operations */\n\tpublic $old;\n\n\t/** @var mixed Is null for remove operations */\n\tpublic $new;\n\n\t/**\n\t * @param self::TYPE_* $type\n\t * @param mixed $old Is null for add operations\n\t * @param mixed $new Is null for remove operations\n\t */\n\tpublic function __construct(int $type, $old, $new)\n\t{\n\t\t$this->type = $type;\n\t\t$this->old = $old;\n\t\t$this->new = $new;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Printer/Differ.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Printer;\n\nuse Exception;\nuse function array_reverse;\nuse function count;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n *\n * Implements the Myers diff algorithm.\n *\n * Myers, Eugene W. \"An O (ND) difference algorithm and its variations.\"\n * Algorithmica 1.1 (1986): 251-266.\n *\n * @template T\n * @internal\n */\nclass Differ\n{\n\n\t/** @var callable(T, T): bool */\n\tprivate $isEqual;\n\n\t/**\n\t * Create differ over the given equality relation.\n\t *\n\t * @param callable(T, T): bool $isEqual Equality relation\n\t */\n\tpublic function __construct(callable $isEqual)\n\t{\n\t\t$this->isEqual = $isEqual;\n\t}\n\n\t/**\n\t * Calculate diff (edit script) from $old to $new.\n\t *\n\t * @param T[] $old Original array\n\t * @param T[] $new New array\n\t *\n\t * @return DiffElem[] Diff (edit script)\n\t */\n\tpublic function diff(array $old, array $new): array\n\t{\n\t\t[$trace, $x, $y] = $this->calculateTrace($old, $new);\n\t\treturn $this->extractDiff($trace, $x, $y, $old, $new);\n\t}\n\n\t/**\n\t * Calculate diff, including \"replace\" operations.\n\t *\n\t * If a sequence of remove operations is followed by the same number of add operations, these\n\t * will be coalesced into replace operations.\n\t *\n\t * @param T[] $old Original array\n\t * @param T[] $new New array\n\t *\n\t * @return DiffElem[] Diff (edit script), including replace operations\n\t */\n\tpublic function diffWithReplacements(array $old, array $new): array\n\t{\n\t\treturn $this->coalesceReplacements($this->diff($old, $new));\n\t}\n\n\t/**\n\t * @param T[] $old\n\t * @param T[] $new\n\t * @return array{array<int, array<int, int>>, int, int}\n\t */\n\tprivate function calculateTrace(array $old, array $new): array\n\t{\n\t\t$n = count($old);\n\t\t$m = count($new);\n\t\t$max = $n + $m;\n\t\t$v = [1 => 0];\n\t\t$trace = [];\n\t\tfor ($d = 0; $d <= $max; $d++) {\n\t\t\t$trace[] = $v;\n\t\t\tfor ($k = -$d; $k <= $d; $k += 2) {\n\t\t\t\tif ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {\n\t\t\t\t\t$x = $v[$k + 1];\n\t\t\t\t} else {\n\t\t\t\t\t$x = $v[$k - 1] + 1;\n\t\t\t\t}\n\n\t\t\t\t$y = $x - $k;\n\t\t\t\twhile ($x < $n && $y < $m && ($this->isEqual)($old[$x], $new[$y])) {\n\t\t\t\t\t$x++;\n\t\t\t\t\t$y++;\n\t\t\t\t}\n\n\t\t\t\t$v[$k] = $x;\n\t\t\t\tif ($x >= $n && $y >= $m) {\n\t\t\t\t\treturn [$trace, $x, $y];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthrow new Exception('Should not happen');\n\t}\n\n\t/**\n\t * @param array<int, array<int, int>> $trace\n\t * @param T[] $old\n\t * @param T[] $new\n\t * @return DiffElem[]\n\t */\n\tprivate function extractDiff(array $trace, int $x, int $y, array $old, array $new): array\n\t{\n\t\t$result = [];\n\t\tfor ($d = count($trace) - 1; $d >= 0; $d--) {\n\t\t\t$v = $trace[$d];\n\t\t\t$k = $x - $y;\n\n\t\t\tif ($k === -$d || ($k !== $d && $v[$k - 1] < $v[$k + 1])) {\n\t\t\t\t$prevK = $k + 1;\n\t\t\t} else {\n\t\t\t\t$prevK = $k - 1;\n\t\t\t}\n\n\t\t\t$prevX = $v[$prevK];\n\t\t\t$prevY = $prevX - $prevK;\n\n\t\t\twhile ($x > $prevX && $y > $prevY) {\n\t\t\t\t$result[] = new DiffElem(DiffElem::TYPE_KEEP, $old[$x - 1], $new[$y - 1]);\n\t\t\t\t$x--;\n\t\t\t\t$y--;\n\t\t\t}\n\n\t\t\tif ($d === 0) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\twhile ($x > $prevX) {\n\t\t\t\t$result[] = new DiffElem(DiffElem::TYPE_REMOVE, $old[$x - 1], null);\n\t\t\t\t$x--;\n\t\t\t}\n\n\t\t\twhile ($y > $prevY) {\n\t\t\t\t$result[] = new DiffElem(DiffElem::TYPE_ADD, null, $new[$y - 1]);\n\t\t\t\t$y--;\n\t\t\t}\n\t\t}\n\t\treturn array_reverse($result);\n\t}\n\n\t/**\n\t * Coalesce equal-length sequences of remove+add into a replace operation.\n\t *\n\t * @param DiffElem[] $diff\n\t * @return DiffElem[]\n\t */\n\tprivate function coalesceReplacements(array $diff): array\n\t{\n\t\t$newDiff = [];\n\t\t$c = count($diff);\n\t\tfor ($i = 0; $i < $c; $i++) {\n\t\t\t$diffType = $diff[$i]->type;\n\t\t\tif ($diffType !== DiffElem::TYPE_REMOVE) {\n\t\t\t\t$newDiff[] = $diff[$i];\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$j = $i;\n\t\t\twhile ($j < $c && $diff[$j]->type === DiffElem::TYPE_REMOVE) {\n\t\t\t\t$j++;\n\t\t\t}\n\n\t\t\t$k = $j;\n\t\t\twhile ($k < $c && $diff[$k]->type === DiffElem::TYPE_ADD) {\n\t\t\t\t$k++;\n\t\t\t}\n\n\t\t\tif ($j - $i === $k - $j) {\n\t\t\t\t$len = $j - $i;\n\t\t\t\tfor ($n = 0; $n < $len; $n++) {\n\t\t\t\t\t$newDiff[] = new DiffElem(\n\t\t\t\t\t\tDiffElem::TYPE_REPLACE,\n\t\t\t\t\t\t$diff[$i + $n]->old,\n\t\t\t\t\t\t$diff[$j + $n]->new,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor (; $i < $k; $i++) {\n\t\t\t\t\t$newDiff[] = $diff[$i];\n\t\t\t\t}\n\t\t\t}\n\t\t\t$i = $k - 1;\n\t\t}\n\t\treturn $newDiff;\n\t}\n\n}\n","/typephp/vendor/phpstan/phpdoc-parser/src/Printer/Printer.php":"<?php declare(strict_types = 1);\n\nnamespace PHPStan\\PhpDocParser\\Printer;\n\nuse LogicException;\nuse PHPStan\\PhpDocParser\\Ast\\Attribute;\nuse PHPStan\\PhpDocParser\\Ast\\Comment;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprArrayNode;\nuse PHPStan\\PhpDocParser\\Ast\\ConstExpr\\ConstExprNode;\nuse PHPStan\\PhpDocParser\\Ast\\Node;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagMethodValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagPropertyValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\AssertTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineAnnotation;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArgument;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArray;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineArrayItem;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\Doctrine\\DoctrineTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ExtendsTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ImplementsTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MethodTagValueParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\MixinTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamClosureThisTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamImmediatelyInvokedCallableTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamLaterInvokedCallableTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamOutTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ParamTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocChildNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PhpDocTextNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PropertyTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PureUnlessCallableIsImpureTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\PureUnlessParameterIsPassedTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireExtendsTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\RequireImplementsTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ReturnTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SealedTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\SelfOutTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TemplateTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\ThrowsTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasImportTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\TypeAliasTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\UsesTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\PhpDoc\\VarTagValueNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayShapeUnsealedTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ArrayTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\CallableTypeParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeForParameterNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConditionalTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ConstTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\GenericTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IdentifierTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\IntersectionTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\InvalidTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\NullableTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeItemNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ObjectShapeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\OffsetAccessTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\ThisTypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\TypeNode;\nuse PHPStan\\PhpDocParser\\Ast\\Type\\UnionTypeNode;\nuse PHPStan\\PhpDocParser\\Lexer\\Lexer;\nuse PHPStan\\PhpDocParser\\Parser\\TokenIterator;\nuse function array_keys;\nuse function array_map;\nuse function assert;\nuse function count;\nuse function get_class;\nuse function get_object_vars;\nuse function implode;\nuse function in_array;\nuse function is_array;\nuse function preg_match_all;\nuse function sprintf;\nuse function str_replace;\nuse function strlen;\nuse function strpos;\nuse function trim;\nuse const PREG_SET_ORDER;\n\n/**\n * Inspired by https://github.com/nikic/PHP-Parser/tree/36a6dcd04e7b0285e8f0868f44bd4927802f7df1\n *\n * Copyright (c) 2011, Nikita Popov\n * All rights reserved.\n */\nfinal class Printer\n{\n\n\t/** @var Differ<Node> */\n\tprivate Differ $differ;\n\n\t/**\n\t * Map From \"{$class}->{$subNode}\" to string that should be inserted\n\t * between elements of this list subnode\n\t *\n\t * @var array<string, string>\n\t */\n\tprivate array $listInsertionMap = [\n\t\tPhpDocNode::class . '->children' => \"\\n * \",\n\t\tUnionTypeNode::class . '->types' => '|',\n\t\tIntersectionTypeNode::class . '->types' => '&',\n\t\tArrayShapeNode::class . '->items' => ', ',\n\t\tObjectShapeNode::class . '->items' => ', ',\n\t\tCallableTypeNode::class . '->parameters' => ', ',\n\t\tCallableTypeNode::class . '->templateTypes' => ', ',\n\t\tGenericTypeNode::class . '->genericTypes' => ', ',\n\t\tConstExprArrayNode::class . '->items' => ', ',\n\t\tMethodTagValueNode::class . '->parameters' => ', ',\n\t\tDoctrineArray::class . '->items' => ', ',\n\t\tDoctrineAnnotation::class . '->arguments' => ', ',\n\t];\n\n\t/**\n\t * [$find, $extraLeft, $extraRight]\n\t *\n\t * @var array<string, array{string|null, string, string}>\n\t */\n\tprivate array $emptyListInsertionMap = [\n\t\tCallableTypeNode::class . '->parameters' => ['(', '', ''],\n\t\tArrayShapeNode::class . '->items' => ['{', '', ''],\n\t\tObjectShapeNode::class . '->items' => ['{', '', ''],\n\t\tDoctrineArray::class . '->items' => ['{', '', ''],\n\t\tDoctrineAnnotation::class . '->arguments' => ['(', '', ''],\n\t];\n\n\t/** @var array<string, list<class-string<TypeNode>>> */\n\tprivate array $parenthesesMap = [\n\t\tCallableTypeNode::class . '->returnType' => [\n\t\t\tCallableTypeNode::class,\n\t\t\tUnionTypeNode::class,\n\t\t\tIntersectionTypeNode::class,\n\t\t],\n\t\tArrayTypeNode::class . '->type' => [\n\t\t\tCallableTypeNode::class,\n\t\t\tUnionTypeNode::class,\n\t\t\tIntersectionTypeNode::class,\n\t\t\tConstTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t\tOffsetAccessTypeNode::class . '->type' => [\n\t\t\tCallableTypeNode::class,\n\t\t\tUnionTypeNode::class,\n\t\t\tIntersectionTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t\tNullableTypeNode::class . '->type' => [\n\t\t\tUnionTypeNode::class,\n\t\t\tIntersectionTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t\tConditionalTypeNode::class . '->subjectType' => [\n\t\t\tUnionTypeNode::class,\n\t\t\tIntersectionTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t];\n\n\t/** @var array<string, list<class-string<TypeNode>>> */\n\tprivate array $parenthesesListMap = [\n\t\tIntersectionTypeNode::class . '->types' => [\n\t\t\tIntersectionTypeNode::class,\n\t\t\tUnionTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t\tUnionTypeNode::class . '->types' => [\n\t\t\tIntersectionTypeNode::class,\n\t\t\tUnionTypeNode::class,\n\t\t\tNullableTypeNode::class,\n\t\t],\n\t];\n\n\tpublic function printFormatPreserving(PhpDocNode $node, PhpDocNode $originalNode, TokenIterator $originalTokens): string\n\t{\n\t\t$this->differ = new Differ(static function ($a, $b) {\n\t\t\tif ($a instanceof Node && $b instanceof Node) {\n\t\t\t\treturn $a === $b->getAttribute(Attribute::ORIGINAL_NODE);\n\t\t\t}\n\n\t\t\treturn false;\n\t\t});\n\n\t\t$tokenIndex = 0;\n\t\t$result = $this->printArrayFormatPreserving(\n\t\t\t$node->children,\n\t\t\t$originalNode->children,\n\t\t\t$originalTokens,\n\t\t\t$tokenIndex,\n\t\t\tPhpDocNode::class,\n\t\t\t'children',\n\t\t);\n\t\tif ($result !== null) {\n\t\t\treturn $result . $originalTokens->getContentBetween($tokenIndex, $originalTokens->getTokenCount());\n\t\t}\n\n\t\treturn $this->print($node);\n\t}\n\n\tpublic function print(Node $node): string\n\t{\n\t\tif ($node instanceof PhpDocNode) {\n\t\t\treturn \"/**\\n *\" . implode(\"\\n *\", array_map(\n\t\t\t\tfunction (PhpDocChildNode $child): string {\n\t\t\t\t\t$s = $this->print($child);\n\t\t\t\t\treturn $s === '' ? '' : ' ' . $s;\n\t\t\t\t},\n\t\t\t\t$node->children,\n\t\t\t)) . \"\\n */\";\n\t\t}\n\t\tif ($node instanceof PhpDocTextNode) {\n\t\t\treturn $node->text;\n\t\t}\n\t\tif ($node instanceof PhpDocTagNode) {\n\t\t\tif ($node->value instanceof DoctrineTagValueNode) {\n\t\t\t\treturn $this->print($node->value);\n\t\t\t}\n\n\t\t\treturn trim(sprintf('%s %s', $node->name, $this->print($node->value)));\n\t\t}\n\t\tif ($node instanceof PhpDocTagValueNode) {\n\t\t\treturn $this->printTagValue($node);\n\t\t}\n\t\tif ($node instanceof TypeNode) {\n\t\t\treturn $this->printType($node);\n\t\t}\n\t\tif ($node instanceof ConstExprNode) {\n\t\t\treturn $this->printConstExpr($node);\n\t\t}\n\t\tif ($node instanceof MethodTagValueParameterNode) {\n\t\t\t$type = $node->type !== null ? $this->print($node->type) . ' ' : '';\n\t\t\t$isReference = $node->isReference ? '&' : '';\n\t\t\t$isVariadic = $node->isVariadic ? '...' : '';\n\t\t\t$default = $node->defaultValue !== null ? ' = ' . $this->print($node->defaultValue) : '';\n\t\t\treturn \"{$type}{$isReference}{$isVariadic}{$node->parameterName}{$default}\";\n\t\t}\n\t\tif ($node instanceof CallableTypeParameterNode) {\n\t\t\t$type = $this->print($node->type) . ' ';\n\t\t\t$isReference = $node->isReference ? '&' : '';\n\t\t\t$isVariadic = $node->isVariadic ? '...' : '';\n\t\t\t$isOptional = $node->isOptional ? '=' : '';\n\t\t\treturn trim(\"{$type}{$isReference}{$isVariadic}{$node->parameterName}\") . $isOptional;\n\t\t}\n\t\tif ($node instanceof ArrayShapeUnsealedTypeNode) {\n\t\t\tif ($node->keyType !== null) {\n\t\t\t\treturn sprintf('<%s, %s>', $this->printType($node->keyType), $this->printType($node->valueType));\n\t\t\t}\n\t\t\treturn sprintf('<%s>', $this->printType($node->valueType));\n\t\t}\n\t\tif ($node instanceof DoctrineAnnotation) {\n\t\t\treturn (string) $node;\n\t\t}\n\t\tif ($node instanceof DoctrineArgument) {\n\t\t\treturn (string) $node;\n\t\t}\n\t\tif ($node instanceof DoctrineArray) {\n\t\t\treturn (string) $node;\n\t\t}\n\t\tif ($node instanceof DoctrineArrayItem) {\n\t\t\treturn (string) $node;\n\t\t}\n\t\tif ($node instanceof ArrayShapeItemNode) {\n\t\t\tif ($node->keyName !== null) {\n\t\t\t\treturn sprintf(\n\t\t\t\t\t'%s%s: %s',\n\t\t\t\t\t$this->print($node->keyName),\n\t\t\t\t\t$node->optional ? '?' : '',\n\t\t\t\t\t$this->printType($node->valueType),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn $this->printType($node->valueType);\n\t\t}\n\t\tif ($node instanceof ObjectShapeItemNode) {\n\t\t\tif ($node->keyName !== null) {\n\t\t\t\treturn sprintf(\n\t\t\t\t\t'%s%s: %s',\n\t\t\t\t\t$this->print($node->keyName),\n\t\t\t\t\t$node->optional ? '?' : '',\n\t\t\t\t\t$this->printType($node->valueType),\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn $this->printType($node->valueType);\n\t\t}\n\n\t\tthrow new LogicException(sprintf('Unknown node type %s', get_class($node)));\n\t}\n\n\tprivate function printTagValue(PhpDocTagValueNode $node): string\n\t{\n\t\t// only nodes that contain another node are handled here\n\t\t// the rest falls back on (string) $node\n\n\t\tif ($node instanceof AssertTagMethodValueNode) {\n\t\t\t$isNegated = $node->isNegated ? '!' : '';\n\t\t\t$isEquality = $node->isEquality ? '=' : '';\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->method}() {$node->description}\");\n\t\t}\n\t\tif ($node instanceof AssertTagPropertyValueNode) {\n\t\t\t$isNegated = $node->isNegated ? '!' : '';\n\t\t\t$isEquality = $node->isEquality ? '=' : '';\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$isNegated}{$isEquality}{$type} {$node->parameter}->{$node->property} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof AssertTagValueNode) {\n\t\t\t$isNegated = $node->isNegated ? '!' : '';\n\t\t\t$isEquality = $node->isEquality ? '=' : '';\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$isNegated}{$isEquality}{$type} {$node->parameter} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ExtendsTagValueNode || $node instanceof ImplementsTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof MethodTagValueNode) {\n\t\t\t$static = $node->isStatic ? 'static ' : '';\n\t\t\t$returnType = $node->returnType !== null ? $this->printType($node->returnType) . ' ' : '';\n\t\t\t$parameters = implode(', ', array_map(fn (MethodTagValueParameterNode $parameter): string => $this->print($parameter), $node->parameters));\n\t\t\t$description = $node->description !== '' ? \" {$node->description}\" : '';\n\t\t\t$templateTypes = count($node->templateTypes) > 0 ? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateTag): string => $this->print($templateTag), $node->templateTypes)) . '>' : '';\n\t\t\treturn \"{$static}{$returnType}{$node->methodName}{$templateTypes}({$parameters}){$description}\";\n\t\t}\n\t\tif ($node instanceof MixinTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof RequireExtendsTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof RequireImplementsTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof SealedTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ParamOutTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ParamTagValueNode) {\n\t\t\t$reference = $node->isReference ? '&' : '';\n\t\t\t$variadic = $node->isVariadic ? '...' : '';\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$reference}{$variadic}{$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ParamImmediatelyInvokedCallableTagValueNode) {\n\t\t\treturn trim(\"{$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ParamLaterInvokedCallableTagValueNode) {\n\t\t\treturn trim(\"{$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ParamClosureThisTagValueNode) {\n\t\t\treturn trim(\"{$node->type} {$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof PureUnlessCallableIsImpureTagValueNode) {\n\t\t\treturn trim(\"{$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof PureUnlessParameterIsPassedTagValueNode) {\n\t\t\treturn trim(\"{$node->parameterName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof PropertyTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->propertyName} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ReturnTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof SelfOutTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim($type . ' ' . $node->description);\n\t\t}\n\t\tif ($node instanceof TemplateTagValueNode) {\n\t\t\t$upperBound = $node->bound !== null ? ' of ' . $this->printType($node->bound) : '';\n\t\t\t$lowerBound = $node->lowerBound !== null ? ' super ' . $this->printType($node->lowerBound) : '';\n\t\t\t$default = $node->default !== null ? ' = ' . $this->printType($node->default) : '';\n\t\t\treturn trim(\"{$node->name}{$upperBound}{$lowerBound}{$default} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof ThrowsTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof TypeAliasImportTagValueNode) {\n\t\t\treturn trim(\n\t\t\t\t\"{$node->importedAlias} from \" . $this->printType($node->importedFrom)\n\t\t\t\t. ($node->importedAs !== null ? \" as {$node->importedAs}\" : ''),\n\t\t\t);\n\t\t}\n\t\tif ($node instanceof TypeAliasTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$node->alias} {$type}\");\n\t\t}\n\t\tif ($node instanceof UsesTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} {$node->description}\");\n\t\t}\n\t\tif ($node instanceof VarTagValueNode) {\n\t\t\t$type = $this->printType($node->type);\n\t\t\treturn trim(\"{$type} \" . trim(\"{$node->variableName} {$node->description}\"));\n\t\t}\n\n\t\treturn (string) $node;\n\t}\n\n\tprivate function printType(TypeNode $node): string\n\t{\n\t\tif ($node instanceof ArrayShapeNode) {\n\t\t\t$items = array_map(fn (ArrayShapeItemNode $item): string => $this->print($item), $node->items);\n\n\t\t\tif (! $node->sealed) {\n\t\t\t\t$items[] = '...' . ($node->unsealedType === null ? '' : $this->print($node->unsealedType));\n\t\t\t}\n\n\t\t\treturn $node->kind . '{' . implode(', ', $items) . '}';\n\t\t}\n\t\tif ($node instanceof ArrayTypeNode) {\n\t\t\treturn $this->printOffsetAccessType($node->type) . '[]';\n\t\t}\n\t\tif ($node instanceof CallableTypeNode) {\n\t\t\tif ($node->returnType instanceof CallableTypeNode || $node->returnType instanceof UnionTypeNode || $node->returnType instanceof IntersectionTypeNode) {\n\t\t\t\t$returnType = $this->wrapInParentheses($node->returnType);\n\t\t\t} else {\n\t\t\t\t$returnType = $this->printType($node->returnType);\n\t\t\t}\n\t\t\t$template = $node->templateTypes !== []\n\t\t\t\t? '<' . implode(', ', array_map(fn (TemplateTagValueNode $templateNode): string => $this->print($templateNode), $node->templateTypes)) . '>'\n\t\t\t\t: '';\n\t\t\t$parameters = implode(', ', array_map(fn (CallableTypeParameterNode $parameterNode): string => $this->print($parameterNode), $node->parameters));\n\t\t\treturn \"{$node->identifier}{$template}({$parameters}): {$returnType}\";\n\t\t}\n\t\tif ($node instanceof ConditionalTypeForParameterNode) {\n\t\t\treturn sprintf(\n\t\t\t\t'(%s %s %s ? %s : %s)',\n\t\t\t\t$node->parameterName,\n\t\t\t\t$node->negated ? 'is not' : 'is',\n\t\t\t\t$this->printType($node->targetType),\n\t\t\t\t$this->printType($node->if),\n\t\t\t\t$this->printType($node->else),\n\t\t\t);\n\t\t}\n\t\tif ($node instanceof ConditionalTypeNode) {\n\t\t\treturn sprintf(\n\t\t\t\t'(%s %s %s ? %s : %s)',\n\t\t\t\t$this->printConditionalSubjectType($node->subjectType),\n\t\t\t\t$node->negated ? 'is not' : 'is',\n\t\t\t\t$this->printType($node->targetType),\n\t\t\t\t$this->printType($node->if),\n\t\t\t\t$this->printType($node->else),\n\t\t\t);\n\t\t}\n\t\tif ($node instanceof ConstTypeNode) {\n\t\t\treturn $this->printConstExpr($node->constExpr);\n\t\t}\n\t\tif ($node instanceof GenericTypeNode) {\n\t\t\t$genericTypes = [];\n\n\t\t\tforeach ($node->genericTypes as $index => $type) {\n\t\t\t\t$variance = $node->variances[$index] ?? GenericTypeNode::VARIANCE_INVARIANT;\n\t\t\t\tif ($variance === GenericTypeNode::VARIANCE_INVARIANT) {\n\t\t\t\t\t$genericTypes[] = $this->printType($type);\n\t\t\t\t} elseif ($variance === GenericTypeNode::VARIANCE_BIVARIANT) {\n\t\t\t\t\t$genericTypes[] = '*';\n\t\t\t\t} else {\n\t\t\t\t\t$genericTypes[] = sprintf('%s %s', $variance, $this->print($type));\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn $node->type . '<' . implode(', ', $genericTypes) . '>';\n\t\t}\n\t\tif ($node instanceof IdentifierTypeNode) {\n\t\t\treturn $node->name;\n\t\t}\n\t\tif ($node instanceof IntersectionTypeNode || $node instanceof UnionTypeNode) {\n\t\t\t$items = [];\n\t\t\tforeach ($node->types as $type) {\n\t\t\t\tif (\n\t\t\t\t\t$type instanceof IntersectionTypeNode\n\t\t\t\t\t|| $type instanceof UnionTypeNode\n\t\t\t\t\t|| $type instanceof NullableTypeNode\n\t\t\t\t) {\n\t\t\t\t\t$items[] = $this->wrapInParentheses($type);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t$items[] = $this->printType($type);\n\t\t\t}\n\n\t\t\treturn implode($node instanceof IntersectionTypeNode ? '&' : '|', $items);\n\t\t}\n\t\tif ($node instanceof InvalidTypeNode) {\n\t\t\treturn (string) $node;\n\t\t}\n\t\tif ($node instanceof NullableTypeNode) {\n\t\t\tif (\n\t\t\t\t$node->type instanceof IntersectionTypeNode\n\t\t\t\t|| $node->type instanceof UnionTypeNode\n\t\t\t\t|| $node->type instanceof NullableTypeNode\n\t\t\t) {\n\t\t\t\treturn '?(' . $this->printType($node->type) . ')';\n\t\t\t}\n\n\t\t\treturn '?' . $this->printType($node->type);\n\t\t}\n\t\tif ($node instanceof ObjectShapeNode) {\n\t\t\t$items = array_map(fn (ObjectShapeItemNode $item): string => $this->print($item), $node->items);\n\n\t\t\treturn 'object{' . implode(', ', $items) . '}';\n\t\t}\n\t\tif ($node instanceof OffsetAccessTypeNode) {\n\t\t\treturn $this->printOffsetAccessType($node->type) . '[' . $this->printType($node->offset) . ']';\n\t\t}\n\t\tif ($node instanceof ThisTypeNode) {\n\t\t\treturn (string) $node;\n\t\t}\n\n\t\tthrow new LogicException(sprintf('Unknown node type %s', get_class($node)));\n\t}\n\n\tprivate function wrapInParentheses(TypeNode $node): string\n\t{\n\t\treturn '(' . $this->printType($node) . ')';\n\t}\n\n\t/**\n\t * What a conditional type asks about, written so that it is read back as\n\t * the very same type.\n\t *\n\t * \"?Foo is Bar ? ... : ...\" and \"Foo|Bar is Baz ? ... : ...\" both read as a\n\t * type followed by something the type says nothing about, so a subject of\n\t * either kind keeps its parentheses.\n\t */\n\tprivate function printConditionalSubjectType(TypeNode $type): string\n\t{\n\t\tif (\n\t\t\t$type instanceof UnionTypeNode\n\t\t\t|| $type instanceof IntersectionTypeNode\n\t\t\t|| $type instanceof NullableTypeNode\n\t\t) {\n\t\t\treturn $this->wrapInParentheses($type);\n\t\t}\n\n\t\treturn $this->printType($type);\n\t}\n\n\tprivate function printOffsetAccessType(TypeNode $type): string\n\t{\n\t\tif (\n\t\t\t$type instanceof CallableTypeNode\n\t\t\t|| $type instanceof UnionTypeNode\n\t\t\t|| $type instanceof IntersectionTypeNode\n\t\t\t|| $type instanceof NullableTypeNode\n\t\t) {\n\t\t\treturn $this->wrapInParentheses($type);\n\t\t}\n\n\t\treturn $this->printType($type);\n\t}\n\n\tprivate function printConstExpr(ConstExprNode $node): string\n\t{\n\t\t// this is fine - ConstExprNode classes do not contain nodes that need smart printer logic\n\t\treturn (string) $node;\n\t}\n\n\t/**\n\t * @param Node[] $nodes\n\t * @param Node[] $originalNodes\n\t */\n\tprivate function printArrayFormatPreserving(array $nodes, array $originalNodes, TokenIterator $originalTokens, int &$tokenIndex, string $parentNodeClass, string $subNodeName): ?string\n\t{\n\t\t$diff = $this->differ->diffWithReplacements($originalNodes, $nodes);\n\t\t$mapKey = $parentNodeClass . '->' . $subNodeName;\n\t\t$insertStr = $this->listInsertionMap[$mapKey] ?? null;\n\t\t$result = '';\n\t\t$beforeFirstKeepOrReplace = true;\n\t\t$delayedAdd = [];\n\n\t\t$insertNewline = false;\n\t\t[$isMultiline, $beforeAsteriskIndent, $afterAsteriskIndent] = $this->isMultiline($tokenIndex, $originalNodes, $originalTokens);\n\n\t\tif ($insertStr === \"\\n * \") {\n\t\t\t$insertStr = sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t}\n\n\t\tforeach ($diff as $i => $diffElem) {\n\t\t\t$diffType = $diffElem->type;\n\t\t\t$arrItem = $diffElem->new;\n\t\t\t$origArrayItem = $diffElem->old;\n\t\t\tif ($diffType === DiffElem::TYPE_KEEP || $diffType === DiffElem::TYPE_REPLACE) {\n\t\t\t\t$beforeFirstKeepOrReplace = false;\n\t\t\t\tif (!$arrItem instanceof Node || !$origArrayItem instanceof Node) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t/** @var int $itemStartPos */\n\t\t\t\t$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);\n\n\t\t\t\t/** @var int $itemEndPos */\n\t\t\t\t$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);\n\n\t\t\t\tif ($itemStartPos < 0 || $itemEndPos < 0 || $itemStartPos < $tokenIndex) {\n\t\t\t\t\tthrow new LogicException();\n\t\t\t\t}\n\n\t\t\t\t$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];\n\t\t\t\t$origComments = $origArrayItem->getAttribute(Attribute::COMMENTS) ?? [];\n\n\t\t\t\t$commentStartPos = count($origComments) > 0 ? $origComments[0]->startIndex : $itemStartPos;\n\t\t\t\tassert($commentStartPos >= 0);\n\n\t\t\t\t$result .= $originalTokens->getContentBetween($tokenIndex, $itemStartPos);\n\n\t\t\t\tif (count($delayedAdd) > 0) {\n\t\t\t\t\tforeach ($delayedAdd as $delayedAddNode) {\n\t\t\t\t\t\t$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])\n\t\t\t\t\t\t\t&& in_array(get_class($delayedAddNode), $this->parenthesesListMap[$mapKey], true);\n\t\t\t\t\t\tif ($parenthesesNeeded) {\n\t\t\t\t\t\t\t$result .= '(';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ($insertNewline) {\n\t\t\t\t\t\t\t$delayedAddComments = $delayedAddNode->getAttribute(Attribute::COMMENTS) ?? [];\n\t\t\t\t\t\t\tif (count($delayedAddComments) > 0) {\n\t\t\t\t\t\t\t\t$result .= $this->printComments($delayedAddComments, $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t\t\t\t$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);\n\t\t\t\t\t\tif ($parenthesesNeeded) {\n\t\t\t\t\t\t\t$result .= ')';\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ($insertNewline) {\n\t\t\t\t\t\t\t$result .= $insertStr . sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t$result .= $insertStr;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$delayedAdd = [];\n\t\t\t\t}\n\n\t\t\t\t$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])\n\t\t\t\t\t&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true)\n\t\t\t\t\t&& !in_array(get_class($origArrayItem), $this->parenthesesListMap[$mapKey], true);\n\t\t\t\t$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($itemStartPos, $itemEndPos);\n\t\t\t\tif ($addParentheses) {\n\t\t\t\t\t$result .= '(';\n\t\t\t\t}\n\n\t\t\t\tif ($comments !== $origComments) {\n\t\t\t\t\tif (count($comments) > 0) {\n\t\t\t\t\t\t$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t\t$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);\n\t\t\t\tif ($addParentheses) {\n\t\t\t\t\t$result .= ')';\n\t\t\t\t}\n\t\t\t\t$tokenIndex = $itemEndPos + 1;\n\n\t\t\t} elseif ($diffType === DiffElem::TYPE_ADD) {\n\t\t\t\tif ($insertStr === null) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t\tif (!$arrItem instanceof Node) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tif ($insertStr === ', ' && $isMultiline || count($arrItem->getAttribute(Attribute::COMMENTS) ?? []) > 0) {\n\t\t\t\t\t$insertStr = ',';\n\t\t\t\t\t$insertNewline = true;\n\t\t\t\t}\n\n\t\t\t\tif ($beforeFirstKeepOrReplace) {\n\t\t\t\t\t// Will be inserted at the next \"replace\" or \"keep\" element\n\t\t\t\t\t$delayedAdd[] = $arrItem;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\t/** @var int $itemEndPos */\n\t\t\t\t$itemEndPos = $tokenIndex - 1;\n\t\t\t\tif ($insertNewline) {\n\t\t\t\t\t$comments = $arrItem->getAttribute(Attribute::COMMENTS) ?? [];\n\t\t\t\t\t$result .= $insertStr;\n\t\t\t\t\tif (count($comments) > 0) {\n\t\t\t\t\t\t$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t\t$result .= $this->printComments($comments, $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t}\n\t\t\t\t\t$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t} else {\n\t\t\t\t\t$result .= $insertStr;\n\t\t\t\t}\n\n\t\t\t\t$parenthesesNeeded = isset($this->parenthesesListMap[$mapKey])\n\t\t\t\t\t&& in_array(get_class($arrItem), $this->parenthesesListMap[$mapKey], true);\n\t\t\t\tif ($parenthesesNeeded) {\n\t\t\t\t\t$result .= '(';\n\t\t\t\t}\n\n\t\t\t\t$result .= $this->printNodeFormatPreserving($arrItem, $originalTokens);\n\t\t\t\tif ($parenthesesNeeded) {\n\t\t\t\t\t$result .= ')';\n\t\t\t\t}\n\n\t\t\t\t$tokenIndex = $itemEndPos + 1;\n\n\t\t\t} elseif ($diffType === DiffElem::TYPE_REMOVE) {\n\t\t\t\tif (!$origArrayItem instanceof Node) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\t/** @var int $itemStartPos */\n\t\t\t\t$itemStartPos = $origArrayItem->getAttribute(Attribute::START_INDEX);\n\n\t\t\t\t/** @var int $itemEndPos */\n\t\t\t\t$itemEndPos = $origArrayItem->getAttribute(Attribute::END_INDEX);\n\t\t\t\tif ($itemStartPos < 0 || $itemEndPos < 0) {\n\t\t\t\t\tthrow new LogicException();\n\t\t\t\t}\n\n\t\t\t\tif ($i === 0) {\n\t\t\t\t\t// If we're removing from the start, keep the tokens before the node and drop those after it,\n\t\t\t\t\t// instead of the other way around.\n\t\t\t\t\t$originalTokensArray = $originalTokens->getTokens();\n\t\t\t\t\tfor ($j = $tokenIndex; $j < $itemStartPos; $j++) {\n\t\t\t\t\t\tif ($originalTokensArray[$j][Lexer::TYPE_OFFSET] === Lexer::TOKEN_PHPDOC_EOL) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\t$result .= $originalTokensArray[$j][Lexer::VALUE_OFFSET];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$tokenIndex = $itemEndPos + 1;\n\t\t\t}\n\t\t}\n\n\t\tif (count($delayedAdd) > 0) {\n\t\t\tif (!isset($this->emptyListInsertionMap[$mapKey])) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\t[$findToken, $extraLeft, $extraRight] = $this->emptyListInsertionMap[$mapKey];\n\t\t\tif ($findToken !== null) {\n\t\t\t\t$originalTokensArray = $originalTokens->getTokens();\n\t\t\t\tfor (; $tokenIndex < count($originalTokensArray); $tokenIndex++) {\n\t\t\t\t\t$result .= $originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET];\n\t\t\t\t\tif ($originalTokensArray[$tokenIndex][Lexer::VALUE_OFFSET] !== $findToken) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t$tokenIndex++;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\t$first = true;\n\t\t\t$result .= $extraLeft;\n\t\t\tforeach ($delayedAdd as $delayedAddNode) {\n\t\t\t\tif (!$first) {\n\t\t\t\t\t$result .= $insertStr;\n\t\t\t\t\tif ($insertNewline) {\n\t\t\t\t\t\t$result .= sprintf('%s%s*%s', $originalTokens->getDetectedNewline() ?? \"\\n\", $beforeAsteriskIndent, $afterAsteriskIndent);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t$result .= $this->printNodeFormatPreserving($delayedAddNode, $originalTokens);\n\t\t\t\t$first = false;\n\t\t\t}\n\t\t\t$result .= $extraRight;\n\t\t}\n\n\t\treturn $result;\n\t}\n\n\t/**\n\t * @param list<Comment> $comments\n\t */\n\tprivate function printComments(array $comments, string $beforeAsteriskIndent, string $afterAsteriskIndent): string\n\t{\n\t\t$formattedComments = [];\n\n\t\tforeach ($comments as $comment) {\n\t\t\t$formattedComments[] = str_replace(\"\\n\", \"\\n\" . $beforeAsteriskIndent . '*' . $afterAsteriskIndent, $comment->getReformattedText());\n\t\t}\n\n\t\treturn implode(\"\\n$beforeAsteriskIndent*$afterAsteriskIndent\", $formattedComments);\n\t}\n\n\t/**\n\t * @param array<Node|null> $nodes\n\t * @return array{bool, string, string}\n\t */\n\tprivate function isMultiline(int $initialIndex, array $nodes, TokenIterator $originalTokens): array\n\t{\n\t\t$isMultiline = count($nodes) > 1;\n\t\t$pos = $initialIndex;\n\t\t$allText = '';\n\t\t/** @var Node|null $node */\n\t\tforeach ($nodes as $node) {\n\t\t\tif (!$node instanceof Node) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$endPos = $node->getAttribute(Attribute::END_INDEX) + 1;\n\t\t\t$text = $originalTokens->getContentBetween($pos, $endPos);\n\t\t\t$allText .= $text;\n\t\t\tif (strpos($text, \"\\n\") === false) {\n\t\t\t\t// We require that a newline is present between *every* item. If the formatting\n\t\t\t\t// is inconsistent, with only some items having newlines, we don't consider it\n\t\t\t\t// as multiline\n\t\t\t\t$isMultiline = false;\n\t\t\t}\n\t\t\t$pos = $endPos;\n\t\t}\n\n\t\t$c = preg_match_all('~\\n(?<before>[\\\\x09\\\\x20]*)\\*(?<after>\\\\x20*)~', $allText, $matches, PREG_SET_ORDER);\n\t\tif ($c === 0) {\n\t\t\treturn [$isMultiline, ' ', '  '];\n\t\t}\n\n\t\t$before = '';\n\t\t$after = '';\n\t\tforeach ($matches as $match) {\n\t\t\tif (strlen($match['before']) > strlen($before)) {\n\t\t\t\t$before = $match['before'];\n\t\t\t}\n\t\t\tif (strlen($match['after']) <= strlen($after)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t$after = $match['after'];\n\t\t}\n\n\t\t$before = strlen($before) === 0 ? ' ' : $before;\n\t\t$after = strlen($after) === 0 ? '  ' : $after;\n\n\t\treturn [$isMultiline, $before, $after];\n\t}\n\n\tprivate function printNodeFormatPreserving(Node $node, TokenIterator $originalTokens): string\n\t{\n\t\t/** @var Node|null $originalNode */\n\t\t$originalNode = $node->getAttribute(Attribute::ORIGINAL_NODE);\n\t\tif ($originalNode === null) {\n\t\t\treturn $this->print($node);\n\t\t}\n\n\t\t$class = get_class($node);\n\t\tif ($class !== get_class($originalNode)) {\n\t\t\tthrow new LogicException();\n\t\t}\n\n\t\t$startPos = $originalNode->getAttribute(Attribute::START_INDEX);\n\t\t$endPos = $originalNode->getAttribute(Attribute::END_INDEX);\n\t\tif ($startPos < 0 || $endPos < 0) {\n\t\t\tthrow new LogicException();\n\t\t}\n\n\t\t$result = '';\n\t\t$pos = $startPos;\n\t\t$subNodeNames = array_keys(get_object_vars($node));\n\t\tforeach ($subNodeNames as $subNodeName) {\n\t\t\t$subNode = $node->$subNodeName;\n\t\t\t$origSubNode = $originalNode->$subNodeName;\n\n\t\t\tif (\n\t\t\t\t(!$subNode instanceof Node && $subNode !== null)\n\t\t\t\t|| (!$origSubNode instanceof Node && $origSubNode !== null)\n\t\t\t) {\n\t\t\t\tif ($subNode === $origSubNode) {\n\t\t\t\t\t// Unchanged, can reuse old code\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (is_array($subNode) && is_array($origSubNode)) {\n\t\t\t\t\t// Array subnode changed, we might be able to reconstruct it\n\t\t\t\t\t$listResult = $this->printArrayFormatPreserving(\n\t\t\t\t\t\t$subNode,\n\t\t\t\t\t\t$origSubNode,\n\t\t\t\t\t\t$originalTokens,\n\t\t\t\t\t\t$pos,\n\t\t\t\t\t\t$class,\n\t\t\t\t\t\t$subNodeName,\n\t\t\t\t\t);\n\n\t\t\t\t\tif ($listResult === null) {\n\t\t\t\t\t\treturn $this->print($node);\n\t\t\t\t\t}\n\n\t\t\t\t\t$result .= $listResult;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\treturn $this->print($node);\n\t\t\t}\n\n\t\t\tif ($origSubNode === null) {\n\t\t\t\tif ($subNode === null) {\n\t\t\t\t\t// Both null, nothing to do\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\treturn $this->print($node);\n\t\t\t}\n\n\t\t\t$subStartPos = $origSubNode->getAttribute(Attribute::START_INDEX);\n\t\t\t$subEndPos = $origSubNode->getAttribute(Attribute::END_INDEX);\n\t\t\tif ($subStartPos < 0 || $subEndPos < 0) {\n\t\t\t\tthrow new LogicException();\n\t\t\t}\n\n\t\t\tif ($subEndPos < $subStartPos) {\n\t\t\t\treturn $this->print($node);\n\t\t\t}\n\n\t\t\tif ($subNode === null) {\n\t\t\t\treturn $this->print($node);\n\t\t\t}\n\n\t\t\t$result .= $originalTokens->getContentBetween($pos, $subStartPos);\n\t\t\t$mapKey = get_class($node) . '->' . $subNodeName;\n\t\t\t$parenthesesNeeded = isset($this->parenthesesMap[$mapKey])\n\t\t\t\t&& in_array(get_class($subNode), $this->parenthesesMap[$mapKey], true);\n\n\t\t\tif ($subNode->getAttribute(Attribute::ORIGINAL_NODE) !== null) {\n\t\t\t\t$parenthesesNeeded = $parenthesesNeeded\n\t\t\t\t\t&& !in_array(get_class($subNode->getAttribute(Attribute::ORIGINAL_NODE)), $this->parenthesesMap[$mapKey], true);\n\t\t\t}\n\n\t\t\t$addParentheses = $parenthesesNeeded && !$originalTokens->hasParentheses($subStartPos, $subEndPos);\n\t\t\tif ($addParentheses) {\n\t\t\t\t$result .= '(';\n\t\t\t}\n\n\t\t\t$result .= $this->printNodeFormatPreserving($subNode, $originalTokens);\n\t\t\tif ($addParentheses) {\n\t\t\t\t$result .= ')';\n\t\t\t}\n\n\t\t\t$pos = $subEndPos + 1;\n\t\t}\n\n\t\treturn $result . $originalTokens->getContentBetween($pos, $endPos + 1);\n\t}\n\n}\n","/typephp/vendor/autoload.php":"<?php\ndeclare(strict_types=1);\n\nspl_autoload_register(function (string $class): bool {\n    $prefixes = [\n        'TypePHP\\\\' => '/typephp/src/',\n        'PhpParser\\\\' => '/typephp/vendor/nikic/php-parser/lib/PhpParser/',\n        'PHPStan\\\\PhpDocParser\\\\' => '/typephp/vendor/phpstan/phpdoc-parser/src/',\n    ];\n\n    foreach ($prefixes as $prefix => $baseDir) {\n        $len = strlen($prefix);\n        if (strncmp($prefix, $class, $len) === 0) {\n            $relativeClass = substr($class, $len);\n            $file = $baseDir . str_replace('\\\\', '/', $relativeClass) . '.php';\n            if (file_exists($file)) {\n                require_once $file;\n                return true;\n            }\n        }\n    }\n    return false;\n});\n"}}